mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-01 01:02:21 +02:00
Compare commits
120 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a42bdf32e1 | |||
| c29d69b44d | |||
| 547b1d07bd | |||
| 22a1dfd354 | |||
| be81e758c6 | |||
| b3117e6410 | |||
| 47ab109c2b | |||
| bc04efbaac | |||
| fbb9d21e73 | |||
| f5308e4287 | |||
| 15b5920e3b | |||
| d09aaab398 | |||
| f7008e2362 | |||
| e939778beb | |||
| 8643b50bd1 | |||
| 74e42525d4 | |||
| 833a387574 | |||
| e574c67ad6 | |||
| ce38d5e891 | |||
| 3a44da4a9d | |||
| eba9106db5 | |||
| 4501226562 | |||
| b974193564 | |||
| 0b3e447258 | |||
| 9908cc02a2 | |||
| 4e67011d7c | |||
| 5f93c0bab3 | |||
| caec5e7c45 | |||
| 240cb4b363 | |||
| 91e8eb66b1 | |||
| 27bd69ec62 | |||
| 553fd39e21 | |||
| 733ee1c6e6 | |||
| ef61c9597d | |||
| e874af791e | |||
| a4b2bb1aa0 | |||
| bc9b20ffc8 | |||
| 6f212328a1 | |||
| a68cde7ac9 | |||
| 5cab331058 | |||
| 6d25a10abd | |||
| d2516947f2 | |||
| 4150d060ee | |||
| 1688076457 | |||
| 5c1f669b2b | |||
| cc1e080ce1 | |||
| 0dfd31a308 | |||
| bd13535d3c | |||
| 27386bb4f0 | |||
| c6c07f03bf | |||
| b0ad08f7c5 | |||
| d1957331b8 | |||
| ffedc04777 | |||
| 684762db58 | |||
| 5a44da3fb0 | |||
| 88cf46d999 | |||
| 906b9413d1 | |||
| 060c4f1529 | |||
| 7902aea849 | |||
| ee22fd8ee8 | |||
| a6e275f8aa | |||
| a61468d600 | |||
| 78c26cb669 | |||
| 0d493c410e | |||
| 80dbbbc1ed | |||
| 81e8872a11 | |||
| 6e1aba6fa0 | |||
| 4220c62ac0 | |||
| 4b73567075 | |||
| fdff0d255a | |||
| e956cf14c4 | |||
| a1646e1b76 | |||
| 5099118dd7 | |||
| 6845ce4984 | |||
| e0d1ad4b52 | |||
| 04b8d0f4a8 | |||
| fe3bf61acb | |||
| 577b9b4635 | |||
| 4b7de188fd | |||
| 3bfb212dc9 | |||
| be7eb41cf3 | |||
| c7db4f528e | |||
| 8a14bc46f6 | |||
| 01ee1a1e49 | |||
| 9d6c9676ab | |||
| 19d8563a76 | |||
| 74e09e1fa9 | |||
| 6533e3e170 | |||
| bfeca771f8 | |||
| f128111650 | |||
| 38fadda762 | |||
| d6d40b01e6 | |||
| bc051f5d81 | |||
| 39bf2190a1 | |||
| b88f81726b | |||
| 24e6cdec62 | |||
| 951671b2f3 | |||
| 21e30545a0 | |||
| 946edb7e16 | |||
| 89c44af374 | |||
| faad451e22 | |||
| 25ef0ecad1 | |||
| efa6caca66 | |||
| 5be4c107f4 | |||
| 65f42dd3e5 | |||
| 287d246777 | |||
| d56f652d0a | |||
| 1f1ef4445f | |||
| 22a669a573 | |||
| f55cce5614 | |||
| a6c3cf1c28 | |||
| cbc803d038 | |||
| a8cefcd0fd | |||
| 2b95dbab22 | |||
| 7a923a947e | |||
| 19e35a7609 | |||
| b8088169ee | |||
| a5594fbb7a | |||
| a733d87c37 | |||
| 79d8ba9ef8 |
@@ -1,5 +1,13 @@
|
||||
# Thanks for your contribution.
|
||||
|
||||
## PLEASE REMOVE
|
||||
To support us in providing a nice (and fast) open-source experience:
|
||||
1. Verify that the tests are passing
|
||||
2. Check that the code is properly formatted (using AndroidStudio's autoformatter)
|
||||
3. Provide write access to the [branch](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork)
|
||||
4. If the PR is not ready for review, please submit it as a [draft](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests)
|
||||
## PLEASE REMOVE
|
||||
|
||||
**Describe the pull request**
|
||||
A clear and concise description of what the pull request changes/adds.
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gradle"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[opentracks.src-main-res-values-strings-xml--main]
|
||||
file_filter = src/main/res/values-<lang>/strings.xml
|
||||
minimum_perc = 0
|
||||
source_file = src/main/res/values/strings.xml
|
||||
source_lang = en
|
||||
type = ANDROID
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# How to contribute?
|
||||
|
||||
## Testing
|
||||
|
||||
Just use OpenTracks and tell us what can be improved by opening an issue [here](https://github.com/OpenTracksApp/OpenTracks/issues/new/choose)
|
||||
|
||||
If we broke things (happens now and then), please tell us also.
|
||||
|
||||
## Coding new features
|
||||
|
||||
You have a cool idea for a feature that is missing in OpenTracks?
|
||||
And you would like to help by implementing it?
|
||||
If not, you can just take a look at the [issue tracker](https://github.com/OpenTracksApp/OpenTracks/issues).
|
||||
|
||||
Advices:
|
||||
* creating an issue beforehand might be a good idea
|
||||
Sometimes it is helpful to discuss your idea and also your implementation approach first.
|
||||
We may be able to give you some hints on how to tackle the problem.
|
||||
It also makes merging your changes easier and, usually, faster.
|
||||
* please only add new dependencies if is absolutely necessary
|
||||
If you need to:
|
||||
* tell us why those are required,
|
||||
* what alternatives are existing, and
|
||||
* why you choose this dependency.
|
||||
And also verify that the license(s) are compatible with _Apache 2.0_ as well as open-source.
|
||||
|
||||
## Coding conventions
|
||||
|
||||
None so far.
|
||||
Just keep it simple.
|
||||
And follow the _scout rule_.
|
||||
|
||||
You can take a look at existing code and get a feeling for it.
|
||||
|
||||
Please autoformat your code using AndroidStudio's code formatter.
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
-194
@@ -1,194 +0,0 @@
|
||||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### Terms and Conditions for use, reproduction, and distribution
|
||||
|
||||
#### 1. Definitions
|
||||
|
||||
“License” shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||
|
||||
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
“Source” form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
“Object” form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
“Contribution” shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
“submitted” means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as “Not a Contribution.”
|
||||
|
||||
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
#### 2. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
#### 3. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
#### 4. Redistribution
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
#### 5. Submission of Contributions
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
#### 6. Trademarks
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
#### 7. Disclaimer of Warranty
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
#### 8. Limitation of Liability
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
#### 9. Accepting Warranty or Additional Liability
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
_END OF TERMS AND CONDITIONS_
|
||||
|
||||
### APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets `[]` replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same “printed page” as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
@@ -13,6 +13,8 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
||||
<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">
|
||||
<br />
|
||||
<img alt="OpenTracks version published on F-Droid" src="https://img.shields.io/f-droid/v/de.dennisguse.opentracks.svg" align="middle" >
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
@@ -61,7 +63,7 @@ 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)).
|
||||
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)).
|
||||
However, this is rather slow and does not provide updates while recording.
|
||||
|
||||
|
||||
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
CHANGELOG_DIR="fastlane/metadata/android/en-US/changelogs/"
|
||||
|
||||
echo "Checking main branch"
|
||||
git checkout main
|
||||
VERSIONID=$(git rev-list HEAD --count main)
|
||||
CHANGELOG_FILE="$CHANGELOG_DIR/$VERSIONID.txt"
|
||||
|
||||
git diff --exit-code || echo -e "\nWARNING WARNING WARNING WARNING WARNING: this branch contains uncommit changes."
|
||||
|
||||
#TODO Execute all tests: we are destroying data, running on a real device.
|
||||
# ./gradlew connectedCheck
|
||||
|
||||
# Changelog
|
||||
echo -e "\nPrevious changelog\n------------"
|
||||
PREVIOUS_CHANGELOG=$(find "$CHANGELOG_DIR" -iname "[[:digit:]]**.txt" | sort -n | tail -1)
|
||||
sed 's/^/>/' "$PREVIOUS_CHANGELOG"
|
||||
|
||||
#For F-Droid, a version starts with a 'v'
|
||||
read -p $'\n\nPlease enter the versionname (e.g., v3.9.5):\n> v' VERSIONNAME
|
||||
VERSIONNAME="v$VERSIONNAME"
|
||||
|
||||
cp "$CHANGELOG_DIR/next_release.txt" "$CHANGELOG_FILE"
|
||||
sed -i "s/(versionName)/$VERSIONNAME/" "$CHANGELOG_FILE"
|
||||
|
||||
echo -e "\nGit commit since last release\n------------"
|
||||
git log $(git describe --tags --abbrev=0)..HEAD --no-merges --oneline
|
||||
|
||||
echo -e "\nPlease edit the changelog for the new release"
|
||||
gedit -w "$CHANGELOG_FILE"
|
||||
git add "$CHANGELOG_FILE"
|
||||
|
||||
echo "Updating build.gradle"
|
||||
sed -i s/versionCode\ .*/versionCode\ "$VERSIONID"/g build.gradle
|
||||
sed -i s/versionName\ .*/versionName\ "\"$VERSIONNAME\""/g build.gradle
|
||||
|
||||
git diff
|
||||
|
||||
COMMIT_MESSAGE="Release: $VERSIONNAME"
|
||||
echo -e "\nCommit message will be: '$COMMIT_MESSAGE'"
|
||||
|
||||
echo -e "\nPress ENTER, if everything looks good."
|
||||
read
|
||||
|
||||
git add -u
|
||||
git commit -m "$COMMIT_MESSAGE"
|
||||
|
||||
echo -e "Next steps:\n1. Push to Github\n2. Create release on Github: https://github.com/OpenTracksApp/OpenTracks/releases"
|
||||
+4
-4
@@ -47,8 +47,8 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "de.dennisguse.opentracks"
|
||||
versionCode 3541
|
||||
versionName "v3.9.2"
|
||||
versionCode 3661
|
||||
versionName "v3.11.1"
|
||||
|
||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||
|
||||
@@ -87,12 +87,12 @@ dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
implementation 'com.google.android.material:material:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
implementation 'com.android.support.constraint:constraint-layout:2.0.1'
|
||||
|
||||
androidTestImplementation 'androidx.test:core:1.3.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test:rules:1.3.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.3.0'
|
||||
androidTestImplementation 'org.mockito:mockito-android:3.4.6'
|
||||
androidTestImplementation 'org.mockito:mockito-android:3.5.13'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
v3.9.3: OpenTracks
|
||||
|
||||
Bugfixes:
|
||||
- Fixed export all tracks bug.
|
||||
@@ -0,0 +1,10 @@
|
||||
v3.9.4: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Added interval computation
|
||||
- Voice announcements present last interval statistics
|
||||
- Settings: Bluetooth icon is animated
|
||||
|
||||
Bugfix:
|
||||
- GPS was not turned off when stopping a recording
|
||||
- Show on map via KML/KMZ/GPX was broken due to refactoring
|
||||
@@ -0,0 +1,8 @@
|
||||
v3.9.5: OpenTracks
|
||||
|
||||
Changes:
|
||||
- UI shows speed only with one fractional digit
|
||||
|
||||
Bugfix:
|
||||
- App crash in search (due to Track.Id refactoring)
|
||||
- Track list did now show if a recording was ongoing (due to Track.Id refactoring)
|
||||
@@ -0,0 +1,10 @@
|
||||
v3.10.0: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Elevation gain via barometer
|
||||
- Add splash screen
|
||||
- Android 11/F-Droid: downgrade to targetSDK 29 (v1 signature)
|
||||
see https://gitlab.com/fdroid/fdroidserver/-/issues/827
|
||||
|
||||
Bugfix:
|
||||
- Several fixes due to trackId refactoring
|
||||
@@ -0,0 +1,10 @@
|
||||
v3.11.0: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Theming: day/night mode (default: night)
|
||||
- Theming: use Material Design instead of custom element theming
|
||||
- Use targetSDK 30 again (F-Droid signs now with V2)
|
||||
|
||||
Bugfix:
|
||||
- Android 11: export all crashed
|
||||
- TrackDetail not updated in UI after data was changed by user
|
||||
@@ -0,0 +1,4 @@
|
||||
v3.11.1: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Voice announcements reported wrong statistics
|
||||
@@ -1,4 +1,4 @@
|
||||
(tbd): OpenTracks
|
||||
(versionName): OpenTracks
|
||||
|
||||
Changes:
|
||||
-
|
||||
|
||||
@@ -19,13 +19,16 @@ import androidx.annotation.NonNull;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests {@link ChartValueSeries}.
|
||||
*
|
||||
@@ -60,16 +63,16 @@ public class ChartValueSeriesTest {
|
||||
|
||||
@Test
|
||||
public void testInitialConditions() {
|
||||
Assert.assertEquals(1, series.getInterval());
|
||||
Assert.assertEquals(0, series.getMinMarkerValue());
|
||||
Assert.assertEquals(5, series.getMaxMarkerValue());
|
||||
Assert.assertTrue(series.isEnabled());
|
||||
assertEquals(1, series.getInterval());
|
||||
assertEquals(0, series.getMinMarkerValue());
|
||||
assertEquals(5, series.getMaxMarkerValue());
|
||||
assertTrue(series.isEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnabled() {
|
||||
series.setEnabled(false);
|
||||
Assert.assertFalse(series.isEnabled());
|
||||
assertFalse(series.isEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -77,9 +80,9 @@ public class ChartValueSeriesTest {
|
||||
series.update(new ChartPoint(0));
|
||||
series.update(new ChartPoint(10));
|
||||
series.updateDimension();
|
||||
Assert.assertEquals(100, series.getInterval());
|
||||
Assert.assertEquals(0, series.getMinMarkerValue());
|
||||
Assert.assertEquals(500, series.getMaxMarkerValue());
|
||||
assertEquals(100, series.getInterval());
|
||||
assertEquals(0, series.getMinMarkerValue());
|
||||
assertEquals(500, series.getMaxMarkerValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -87,9 +90,9 @@ public class ChartValueSeriesTest {
|
||||
series.update(new ChartPoint(0));
|
||||
series.update(new ChartPoint(901));
|
||||
series.updateDimension();
|
||||
Assert.assertEquals(1000, series.getInterval());
|
||||
Assert.assertEquals(0, series.getMinMarkerValue());
|
||||
Assert.assertEquals(5000, series.getMaxMarkerValue());
|
||||
assertEquals(1000, series.getInterval());
|
||||
assertEquals(0, series.getMinMarkerValue());
|
||||
assertEquals(5000, series.getMaxMarkerValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -97,8 +100,8 @@ public class ChartValueSeriesTest {
|
||||
series.update(new ChartPoint(220));
|
||||
series.update(new ChartPoint(250));
|
||||
series.updateDimension();
|
||||
Assert.assertEquals(100, series.getInterval());
|
||||
Assert.assertEquals(200, series.getMinMarkerValue());
|
||||
Assert.assertEquals(700, series.getMaxMarkerValue());
|
||||
assertEquals(100, series.getInterval());
|
||||
assertEquals(200, series.getMinMarkerValue());
|
||||
assertEquals(700, series.getMaxMarkerValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.content.Context;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -31,6 +30,8 @@ import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link DescriptionGenerator}.
|
||||
*
|
||||
@@ -85,7 +86,7 @@ public class DescriptionGeneratorTest {
|
||||
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
||||
|
||||
Assert.assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,7 +120,7 @@ public class DescriptionGeneratorTest {
|
||||
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
||||
|
||||
Assert.assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +131,7 @@ public class DescriptionGeneratorTest {
|
||||
public void testWriteDistance() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
descriptionGenerator.writeDistance(1100, builder, R.string.description_total_distance, "<br>");
|
||||
Assert.assertEquals("Total distance: 1.10 km (0.7 mi)<br>", builder.toString());
|
||||
assertEquals("Total distance: 1.10 km (0.7 mi)<br>", builder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +141,7 @@ public class DescriptionGeneratorTest {
|
||||
public void testWriteTime() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
descriptionGenerator.writeTime(1000, builder, R.string.description_total_time, "<br>");
|
||||
Assert.assertEquals("Total time: 00:01<br>", builder.toString());
|
||||
assertEquals("Total time: 00:01<br>", builder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,7 +151,7 @@ public class DescriptionGeneratorTest {
|
||||
public void testWriteSpeed() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
descriptionGenerator.writeSpeed(1.1, builder, R.string.description_average_speed, "\n");
|
||||
Assert.assertEquals("Average speed: 3.96 km/h (2.5 mi/h)\n", builder.toString());
|
||||
assertEquals("Average speed: 3.96 km/h (2.5 mi/h)\n", builder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +161,7 @@ public class DescriptionGeneratorTest {
|
||||
public void testWriteElevation() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
descriptionGenerator.writeElevation(4.2, builder, R.string.description_min_elevation, "<br>");
|
||||
Assert.assertEquals("Min elevation: 4 m (14 ft)<br>", builder.toString());
|
||||
assertEquals("Min elevation: 4 m (14 ft)<br>", builder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,6 +171,6 @@ public class DescriptionGeneratorTest {
|
||||
public void testWritePace() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
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());
|
||||
assertEquals("Average pace: 15:09 min/km (24:23 min/mi)\n", builder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.provider.ProviderTestRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -35,13 +34,17 @@ import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.content.SearchEngine.ScoredResult;
|
||||
import de.dennisguse.opentracks.content.SearchEngine.SearchQuery;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
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.content.provider.CustomContentProvider;
|
||||
import de.dennisguse.opentracks.content.provider.CustomSQLiteOpenHelper;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* Tests for {@link SearchEngine}.
|
||||
* These are not meant to be quality tests, but instead feature-by-feature tests.
|
||||
@@ -99,36 +102,36 @@ public class SearchEngineTest {
|
||||
return insertTrack(title, "", "", hoursAgo);
|
||||
}
|
||||
|
||||
private Waypoint.Id insertWaypoint(String title, String description, String category, double distance, long hoursAgo, Track.Id trackId) {
|
||||
private Marker.Id insertWaypoint(String title, String description, String category, double distance, long hoursAgo, Track.Id trackId) {
|
||||
Location location = new Location(HERE);
|
||||
location.setLatitude(location.getLatitude() + distance);
|
||||
location.setLongitude(location.getLongitude() + distance);
|
||||
if (hoursAgo >= 0) {
|
||||
location.setTime(NOW - hoursAgo * 1000L * 60L * 60L);
|
||||
}
|
||||
Waypoint waypoint = new Waypoint(location);
|
||||
Marker waypoint = new Marker(location);
|
||||
waypoint.setName(title);
|
||||
waypoint.setDescription(description);
|
||||
waypoint.setCategory(category);
|
||||
waypoint.setTrackId(trackId);
|
||||
|
||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
||||
return new Waypoint.Id(ContentUris.parseId(uri));
|
||||
Uri uri = providerUtils.insertMarker(waypoint);
|
||||
return new Marker.Id(ContentUris.parseId(uri));
|
||||
}
|
||||
|
||||
private Waypoint.Id insertWaypoint(String title, String description, String category) {
|
||||
private Marker.Id insertWaypoint(String title, String description, String category) {
|
||||
return insertWaypoint(title, description, category, 0.0, -1, null);
|
||||
}
|
||||
|
||||
private Waypoint.Id insertWaypoint(String title, double distance) {
|
||||
private Marker.Id insertWaypoint(String title, double distance) {
|
||||
return insertWaypoint(title, "", "", distance, -1, null);
|
||||
}
|
||||
|
||||
private Waypoint.Id insertWaypoint(String title, long hoursAgo) {
|
||||
private Marker.Id insertWaypoint(String title, long hoursAgo) {
|
||||
return insertWaypoint(title, "", "", 0.0, hoursAgo, null);
|
||||
}
|
||||
|
||||
private Waypoint.Id insertWaypoint(String title, long hoursAgo, Track.Id trackId) {
|
||||
private Marker.Id insertWaypoint(String title, long hoursAgo, Track.Id trackId) {
|
||||
return insertWaypoint(title, "", "", 0.0, hoursAgo, trackId);
|
||||
}
|
||||
|
||||
@@ -168,12 +171,12 @@ public class SearchEngineTest {
|
||||
// - one which will match in title and description
|
||||
// - one which will match in all fields
|
||||
insertWaypoint("bb", "cc", "dd");
|
||||
Waypoint.Id descriptionMatchId = insertWaypoint("bb", "aa", "cc");
|
||||
Waypoint.Id categoryMatchId = insertWaypoint("bb", "cc", "aa");
|
||||
Waypoint.Id titleMatchId = insertWaypoint("aa", "bb", "cc");
|
||||
Waypoint.Id titleCategoryMatchId = insertWaypoint("aa", "bb", "ca");
|
||||
Waypoint.Id titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc");
|
||||
Waypoint.Id allMatchId = insertWaypoint("aa", "ba", "ca");
|
||||
Marker.Id descriptionMatchId = insertWaypoint("bb", "aa", "cc");
|
||||
Marker.Id categoryMatchId = insertWaypoint("bb", "cc", "aa");
|
||||
Marker.Id titleMatchId = insertWaypoint("aa", "bb", "cc");
|
||||
Marker.Id titleCategoryMatchId = insertWaypoint("aa", "bb", "ca");
|
||||
Marker.Id titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc");
|
||||
Marker.Id allMatchId = insertWaypoint("aa", "ba", "ca");
|
||||
|
||||
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||
@@ -190,9 +193,9 @@ public class SearchEngineTest {
|
||||
// - one waypoint which will match by title
|
||||
// - one track which won't match
|
||||
// - one track which will match by title
|
||||
Waypoint.Id descriptionWaypointId = insertWaypoint("bb", "aa", "cc");
|
||||
Marker.Id descriptionWaypointId = insertWaypoint("bb", "aa", "cc");
|
||||
insertWaypoint("bb", "cc", "dd");
|
||||
Waypoint.Id titleWaypointId = insertWaypoint("aa", "bb", "cc");
|
||||
Marker.Id titleWaypointId = insertWaypoint("aa", "bb", "cc");
|
||||
insertTrack("bb", "cc", "dd");
|
||||
Track.Id trackId = insertTrack("aa", "bb", "cc");
|
||||
|
||||
@@ -200,7 +203,7 @@ public class SearchEngineTest {
|
||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||
|
||||
// Title > Description > Category.
|
||||
Assert.assertEquals(results.toString(), 3, results.size());
|
||||
assertEquals(results.toString(), 3, results.size());
|
||||
assertTrackResult(trackId, results.get(0));
|
||||
assertWaypointResult(titleWaypointId, results.get(1));
|
||||
assertWaypointResult(descriptionWaypointId, results.get(2));
|
||||
@@ -209,9 +212,9 @@ public class SearchEngineTest {
|
||||
@Test
|
||||
public void testSearchWaypointDistance() {
|
||||
// All results match text, but they're at difference distances from the user.
|
||||
Waypoint.Id farFarAwayId = insertWaypoint("aa", 0.3);
|
||||
Waypoint.Id nearId = insertWaypoint("ab", 0.1);
|
||||
Waypoint.Id farId = insertWaypoint("ac", 0.2);
|
||||
Marker.Id farFarAwayId = insertWaypoint("aa", 0.3);
|
||||
Marker.Id nearId = insertWaypoint("ab", 0.1);
|
||||
Marker.Id farId = insertWaypoint("ac", 0.2);
|
||||
|
||||
SearchQuery query = new SearchQuery("a", HERE, null, NOW);
|
||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||
@@ -236,9 +239,9 @@ public class SearchEngineTest {
|
||||
@Test
|
||||
public void testSearchWaypointRecent() {
|
||||
// All results match text, but they're were recorded at different times.
|
||||
Waypoint.Id oldestId = insertWaypoint("aa", 2);
|
||||
Waypoint.Id recentId = insertWaypoint("ab", 0);
|
||||
Waypoint.Id oldId = insertWaypoint("ac", 1);
|
||||
Marker.Id oldestId = insertWaypoint("aa", 2);
|
||||
Marker.Id recentId = insertWaypoint("ab", 0);
|
||||
Marker.Id oldId = insertWaypoint("ac", 1);
|
||||
|
||||
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||
@@ -263,8 +266,8 @@ public class SearchEngineTest {
|
||||
@Test
|
||||
public void testSearchCurrentTrackWaypoint() {
|
||||
// All results match text, but one of them is in the current track.
|
||||
Waypoint.Id otherId = insertWaypoint("aa", 1, new Track.Id(456));
|
||||
Waypoint.Id currentId = insertWaypoint("ab", 1, new Track.Id(123));
|
||||
Marker.Id otherId = insertWaypoint("aa", 1, new Track.Id(456));
|
||||
Marker.Id currentId = insertWaypoint("ab", 1, new Track.Id(123));
|
||||
|
||||
SearchQuery query = new SearchQuery("a", null, new Track.Id(123), NOW);
|
||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||
@@ -274,9 +277,9 @@ public class SearchEngineTest {
|
||||
}
|
||||
|
||||
private void assertTrackResult(Track.Id trackId, ScoredResult result) {
|
||||
Assert.assertNotNull("Not a track", result.track);
|
||||
Assert.assertNull("Ambiguous result", result.waypoint);
|
||||
Assert.assertEquals(trackId, result.track.getId());
|
||||
assertNotNull("Not a track", result.track);
|
||||
assertNull("Ambiguous result", result.marker);
|
||||
assertEquals(trackId, result.track.getId());
|
||||
}
|
||||
|
||||
private void assertTrackResults(List<ScoredResult> results, Track.Id... trackIds) {
|
||||
@@ -286,34 +289,34 @@ public class SearchEngineTest {
|
||||
}
|
||||
|
||||
String errMsg = "Expected IDs=" + Arrays.toString(longTrackIds) + "; results=" + results;
|
||||
Assert.assertEquals(results.size(), trackIds.length);
|
||||
assertEquals(results.size(), trackIds.length);
|
||||
for (int i = 0; i < results.size(); i++) {
|
||||
ScoredResult result = results.get(i);
|
||||
Assert.assertNotNull(errMsg, result.track);
|
||||
Assert.assertNull(errMsg, result.waypoint);
|
||||
Assert.assertEquals(errMsg, trackIds[i], result.track.getId());
|
||||
assertNotNull(errMsg, result.track);
|
||||
assertNull(errMsg, result.marker);
|
||||
assertEquals(errMsg, trackIds[i], result.track.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void assertWaypointResult(Waypoint.Id waypointId, ScoredResult result) {
|
||||
Assert.assertNotNull("Not a waypoint", result.waypoint);
|
||||
Assert.assertNull("Ambiguous result", result.track);
|
||||
Assert.assertEquals(waypointId, result.waypoint.getId());
|
||||
private void assertWaypointResult(Marker.Id waypointId, ScoredResult result) {
|
||||
assertNotNull("Not a waypoint", result.marker);
|
||||
assertNull("Ambiguous result", result.track);
|
||||
assertEquals(waypointId, result.marker.getId());
|
||||
}
|
||||
|
||||
private void assertWaypointResults(List<ScoredResult> results, Waypoint.Id... waypointIds) {
|
||||
private void assertWaypointResults(List<ScoredResult> results, Marker.Id... waypointIds) {
|
||||
long[] longWaypointIds = new long[waypointIds.length];
|
||||
for (int i = 0; i < waypointIds.length; i++) {
|
||||
longWaypointIds[i] = waypointIds[i].getId();
|
||||
}
|
||||
|
||||
String errMsg = "Expected IDs=" + Arrays.toString(longWaypointIds) + "; results=" + results;
|
||||
Assert.assertEquals(results.size(), waypointIds.length);
|
||||
assertEquals(results.size(), waypointIds.length);
|
||||
for (int i = 0; i < results.size(); i++) {
|
||||
ScoredResult result = results.get(i);
|
||||
Assert.assertNotNull(errMsg, result.waypoint);
|
||||
Assert.assertNull(errMsg, result.track);
|
||||
Assert.assertEquals(errMsg, waypointIds[i], result.waypoint.getId());
|
||||
assertNotNull(errMsg, result.marker);
|
||||
assertNull(errMsg, result.track);
|
||||
assertEquals(errMsg, waypointIds[i], result.marker.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +68,9 @@ public class TestDataUtil {
|
||||
trackPoint.setSpeed(5f + (i / 10));
|
||||
|
||||
trackPoint.setHeartRate_bpm(100f + i);
|
||||
trackPoint.setCyclingCadence_rpm(200f + i);
|
||||
trackPoint.setCyclingCadence_rpm(300f + i);
|
||||
trackPoint.setPower(400f + i);
|
||||
trackPoint.setElevationGain(500f + i);
|
||||
return trackPoint;
|
||||
}
|
||||
|
||||
@@ -93,12 +93,12 @@ public class TestDataUtil {
|
||||
* @param location The location.
|
||||
* @return the Waypoint created.
|
||||
*/
|
||||
public static Waypoint createWaypointWithPhoto(Context context, Track.Id trackId, Location location) throws IOException {
|
||||
public static Marker createWaypointWithPhoto(Context context, Track.Id trackId, Location location) throws IOException {
|
||||
File dstFile = new File(FileUtils.getImageUrl(context, trackId));
|
||||
dstFile.createNewFile();
|
||||
Uri photoUri = FileUtils.getUriForFile(context, dstFile);
|
||||
String photoUrl = photoUri.toString();
|
||||
|
||||
return new Waypoint("Waypoint name", "Waypoint description", "Waypoint category", "", trackId, 0.0, 0, location, photoUrl);
|
||||
return new Marker("Waypoint name", "Waypoint description", "Waypoint category", "", trackId, 0.0, 0, location, photoUrl);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -25,9 +25,9 @@ import androidx.test.core.app.ApplicationProvider;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -67,7 +67,7 @@ public class CustomContentProviderTest {
|
||||
assertEquals(TrackPointsColumns.CONTENT_TYPE, customContentProvider.getType(TrackPointsColumns.CONTENT_URI_BY_ID));
|
||||
assertEquals(TrackPointsColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(TrackPointsColumns.CONTENT_URI_BY_TRACKID.buildUpon(), 1).build()));
|
||||
|
||||
assertEquals(WaypointsColumns.CONTENT_TYPE, customContentProvider.getType(WaypointsColumns.CONTENT_URI));
|
||||
assertEquals(WaypointsColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(WaypointsColumns.CONTENT_URI.buildUpon(), 1).build()));
|
||||
assertEquals(MarkerColumns.CONTENT_TYPE, customContentProvider.getType(MarkerColumns.CONTENT_URI));
|
||||
assertEquals(MarkerColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(MarkerColumns.CONTENT_URI.buildUpon(), 1).build()));
|
||||
}
|
||||
}
|
||||
+211
-207
@@ -25,7 +25,6 @@ import android.util.Pair;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -39,17 +38,22 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
import de.dennisguse.opentracks.util.UUIDUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
@@ -122,13 +126,13 @@ public class CustomContentProviderUtilsTest {
|
||||
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(trackId, -1L, descending)) {
|
||||
while (it.hasNext()) {
|
||||
TrackPoint loc = it.next();
|
||||
Assert.assertNotNull(loc);
|
||||
assertNotNull(loc);
|
||||
locations.add(loc);
|
||||
// Make sure the IDs are returned in the right order.
|
||||
Assert.assertEquals(descending ? lastPointId - locations.size() + 1
|
||||
assertEquals(descending ? lastPointId - locations.size() + 1
|
||||
: lastPointId - numPoints + locations.size(), it.getTrackPointId());
|
||||
}
|
||||
Assert.assertEquals(numPoints, locations.size());
|
||||
assertEquals(numPoints, locations.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +142,7 @@ public class CustomContentProviderUtilsTest {
|
||||
track.setName("Test: " + id.getId());
|
||||
contentProviderUtils.insertTrack(track);
|
||||
track = contentProviderUtils.getTrack(id);
|
||||
Assert.assertNotNull(track);
|
||||
assertNotNull(track);
|
||||
|
||||
TrackPoint[] trackPoints = new TrackPoint[numPoints];
|
||||
for (int i = 0; i < numPoints; ++i) {
|
||||
@@ -162,8 +166,8 @@ public class CustomContentProviderUtilsTest {
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertTrue(numPoints == 0 || lastPointId > 0);
|
||||
Assert.assertEquals(numPoints, counter);
|
||||
assertTrue(numPoints == 0 || lastPointId > 0);
|
||||
assertEquals(numPoints, counter);
|
||||
|
||||
return lastPointId;
|
||||
}
|
||||
@@ -195,8 +199,8 @@ public class CustomContentProviderUtilsTest {
|
||||
when(cursorMock.getString(columnIndex)).thenReturn(name);
|
||||
|
||||
Track track = contentProviderUtils.createTrack(cursorMock);
|
||||
Assert.assertEquals(trackId, track.getId());
|
||||
Assert.assertEquals(name, track.getName());
|
||||
assertEquals(trackId, track.getId());
|
||||
assertEquals(name, track.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,25 +212,25 @@ public class CustomContentProviderUtilsTest {
|
||||
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||
|
||||
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
contentProviderUtils.insertWaypoint(waypoint);
|
||||
Marker waypoint = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
contentProviderUtils.insertMarker(waypoint);
|
||||
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
Assert.assertEquals(1, tracksCursor.getCount());
|
||||
assertEquals(1, tracksCursor.getCount());
|
||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, 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());
|
||||
assertEquals(10, tracksPointsCursor.getCount());
|
||||
Cursor waypointCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(1, waypointCursor.getCount());
|
||||
// Delete all.
|
||||
contentProviderUtils.deleteAllTracks(context);
|
||||
// Check whether all have been deleted.
|
||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
Assert.assertEquals(0, tracksCursor.getCount());
|
||||
assertEquals(0, tracksCursor.getCount());
|
||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, 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());
|
||||
assertEquals(0, tracksPointsCursor.getCount());
|
||||
waypointCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(0, waypointCursor.getCount());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,32 +243,32 @@ public class CustomContentProviderUtilsTest {
|
||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||
|
||||
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
||||
Waypoint waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
contentProviderUtils.insertWaypoint(waypoint);
|
||||
Marker waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
contentProviderUtils.insertMarker(waypoint);
|
||||
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
Assert.assertEquals(1, tracksCursor.getCount());
|
||||
assertEquals(1, tracksCursor.getCount());
|
||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, 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());
|
||||
assertEquals(10, tracksPointsCursor.getCount());
|
||||
Cursor waypointCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(1, waypointCursor.getCount());
|
||||
// Check waypoint has photo and it's in the external storage.
|
||||
Assert.assertTrue(waypoint.hasPhoto());
|
||||
assertTrue(waypoint.hasPhoto());
|
||||
File dir = FileUtils.getPhotoDir(context, trackId);
|
||||
Assert.assertTrue(dir.isDirectory());
|
||||
Assert.assertEquals(1, dir.list().length);
|
||||
Assert.assertTrue(dir.exists());
|
||||
assertTrue(dir.isDirectory());
|
||||
assertEquals(1, dir.list().length);
|
||||
assertTrue(dir.exists());
|
||||
// Delete all.
|
||||
contentProviderUtils.deleteAllTracks(context);
|
||||
// Check whether all have been deleted.
|
||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
Assert.assertEquals(0, tracksCursor.getCount());
|
||||
assertEquals(0, tracksCursor.getCount());
|
||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, 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());
|
||||
Assert.assertFalse(dir.exists());
|
||||
assertEquals(0, tracksPointsCursor.getCount());
|
||||
waypointCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(0, waypointCursor.getCount());
|
||||
assertFalse(dir.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,26 +287,26 @@ public class CustomContentProviderUtilsTest {
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId2, 10);
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId3, 10);
|
||||
|
||||
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId2));
|
||||
Marker waypoint = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId2));
|
||||
waypoint.setTrackId(trackId1);
|
||||
contentProviderUtils.insertWaypoint(waypoint);
|
||||
contentProviderUtils.insertMarker(waypoint);
|
||||
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
Assert.assertEquals(3, tracksCursor.getCount());
|
||||
assertEquals(3, tracksCursor.getCount());
|
||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, 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());
|
||||
assertEquals(20, tracksPointsCursor.getCount());
|
||||
Cursor waypointCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(1, waypointCursor.getCount());
|
||||
// Delete one track.
|
||||
contentProviderUtils.deleteTrack(context, trackId1);
|
||||
// Check whether all data of a track has been deleted.
|
||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
Assert.assertEquals(2, tracksCursor.getCount());
|
||||
assertEquals(2, tracksCursor.getCount());
|
||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, 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());
|
||||
assertEquals(20, tracksPointsCursor.getCount());
|
||||
waypointCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(0, waypointCursor.getCount());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,41 +326,41 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// Insert a waypoint in tracks trackId and trackId + 1.
|
||||
TrackPoint trackPoint1 = contentProviderUtils.getLastValidTrackPoint(trackId1);
|
||||
Waypoint waypoint1 = TestDataUtil.createWaypointWithPhoto(context, trackId1, trackPoint1.getLocation());
|
||||
contentProviderUtils.insertWaypoint(waypoint1);
|
||||
Marker waypoint1 = TestDataUtil.createWaypointWithPhoto(context, trackId1, trackPoint1.getLocation());
|
||||
contentProviderUtils.insertMarker(waypoint1);
|
||||
File dir1 = FileUtils.getPhotoDir(context, trackId1);
|
||||
|
||||
TrackPoint trackPoint2 = contentProviderUtils.getLastValidTrackPoint(trackId2);
|
||||
Waypoint waypoint2 = TestDataUtil.createWaypointWithPhoto(context, trackId2, trackPoint2.getLocation());
|
||||
contentProviderUtils.insertWaypoint(waypoint2);
|
||||
Marker waypoint2 = TestDataUtil.createWaypointWithPhoto(context, trackId2, trackPoint2.getLocation());
|
||||
contentProviderUtils.insertMarker(waypoint2);
|
||||
File dir2 = FileUtils.getPhotoDir(context, trackId2);
|
||||
|
||||
// Check.
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
Assert.assertEquals(3, tracksCursor.getCount());
|
||||
assertEquals(3, tracksCursor.getCount());
|
||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
||||
Assert.assertEquals(30, tracksPointsCursor.getCount());
|
||||
Cursor waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null, null, WaypointsColumns._ID);
|
||||
Assert.assertEquals(2, waypointCursor.getCount());
|
||||
Assert.assertTrue(waypoint1.hasPhoto());
|
||||
Assert.assertTrue(dir1.isDirectory());
|
||||
Assert.assertEquals(1, dir1.list().length);
|
||||
Assert.assertTrue(dir1.exists());
|
||||
Assert.assertTrue(dir2.isDirectory());
|
||||
Assert.assertEquals(1, dir2.list().length);
|
||||
Assert.assertTrue(dir2.exists());
|
||||
assertEquals(30, tracksPointsCursor.getCount());
|
||||
Cursor waypointCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(2, waypointCursor.getCount());
|
||||
assertTrue(waypoint1.hasPhoto());
|
||||
assertTrue(dir1.isDirectory());
|
||||
assertEquals(1, dir1.list().length);
|
||||
assertTrue(dir1.exists());
|
||||
assertTrue(dir2.isDirectory());
|
||||
assertEquals(1, dir2.list().length);
|
||||
assertTrue(dir2.exists());
|
||||
// Delete one track.
|
||||
contentProviderUtils.deleteTrack(context, trackId1);
|
||||
// Check whether all data of a track has been deleted.
|
||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
Assert.assertEquals(2, tracksCursor.getCount());
|
||||
assertEquals(2, tracksCursor.getCount());
|
||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
||||
Assert.assertEquals(20, tracksPointsCursor.getCount());
|
||||
waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null, null, WaypointsColumns._ID);
|
||||
Assert.assertEquals(1, waypointCursor.getCount());
|
||||
Assert.assertFalse(dir1.exists());
|
||||
Assert.assertTrue(dir2.exists());
|
||||
assertEquals(20, tracksPointsCursor.getCount());
|
||||
waypointCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(1, waypointCursor.getCount());
|
||||
assertFalse(dir1.exists());
|
||||
assertTrue(dir2.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,8 +377,8 @@ public class CustomContentProviderUtilsTest {
|
||||
List<Track> allTracks = contentProviderUtils.getTracks();
|
||||
|
||||
// then
|
||||
Assert.assertEquals(initialTrackNumber + 1, allTracks.size());
|
||||
Assert.assertEquals(trackId, allTracks.get(allTracks.size() - 1).getId());
|
||||
assertEquals(initialTrackNumber + 1, allTracks.size());
|
||||
assertEquals(trackId, allTracks.get(allTracks.size() - 1).getId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -384,7 +388,7 @@ public class CustomContentProviderUtilsTest {
|
||||
public void testGetLastTrack() {
|
||||
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||
contentProviderUtils.insertTrack(TestDataUtil.createTrack(trackId));
|
||||
Assert.assertEquals(trackId, contentProviderUtils.getLastTrack().getId());
|
||||
assertEquals(trackId, contentProviderUtils.getLastTrack().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,7 +401,7 @@ public class CustomContentProviderUtilsTest {
|
||||
contentProviderUtils.insertTrack(TestDataUtil.createTrack(trackId));
|
||||
|
||||
// when / then
|
||||
Assert.assertNotNull(contentProviderUtils.getTrack(trackId));
|
||||
assertNotNull(contentProviderUtils.getTrack(trackId));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,7 +415,7 @@ public class CustomContentProviderUtilsTest {
|
||||
contentProviderUtils.insertTrack(track);
|
||||
|
||||
// when / then
|
||||
Assert.assertNotNull(contentProviderUtils.getTrack(track.getUuid()));
|
||||
assertNotNull(contentProviderUtils.getTrack(track.getUuid()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -428,14 +432,14 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// when / then
|
||||
contentProviderUtils.insertTrack(track);
|
||||
Assert.assertEquals(nameOld, contentProviderUtils.getTrack(trackId).getName());
|
||||
assertEquals(nameOld, contentProviderUtils.getTrack(trackId).getName());
|
||||
track.setName(nameNew);
|
||||
contentProviderUtils.updateTrack(track);
|
||||
Assert.assertEquals(nameNew, contentProviderUtils.getTrack(trackId).getName());
|
||||
assertEquals(nameNew, contentProviderUtils.getTrack(trackId).getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#createContentValues(Waypoint)}.
|
||||
* Tests the method {@link ContentProviderUtils#createContentValues(Marker)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCreateContentValues_waypoint() {
|
||||
@@ -451,7 +455,7 @@ public class CustomContentProviderUtilsTest {
|
||||
statistics.setTotalTime(1500L);
|
||||
statistics.setMovingTime(700L);
|
||||
statistics.setTotalDistance(750.0);
|
||||
statistics.setTotalElevationGain(50.0);
|
||||
statistics.setTotalElevationGain(50.0f);
|
||||
statistics.setMaxSpeed(60.0);
|
||||
statistics.setMaxElevation(1250.0);
|
||||
statistics.setMinElevation(1200.0);
|
||||
@@ -459,30 +463,30 @@ public class CustomContentProviderUtilsTest {
|
||||
track.first.setTrackStatistics(statistics);
|
||||
contentProviderUtils.insertTrack(track.first);
|
||||
|
||||
Waypoint waypoint = new Waypoint(track.second[0]);
|
||||
Marker waypoint = new Marker(track.second[0]);
|
||||
waypoint.setDescription(TEST_DESC);
|
||||
contentProviderUtils.insertWaypoint(waypoint);
|
||||
contentProviderUtils.insertMarker(waypoint);
|
||||
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(contentResolverMock);
|
||||
|
||||
Waypoint.Id waypointId = new Waypoint.Id(System.currentTimeMillis());
|
||||
Marker.Id waypointId = new Marker.Id(System.currentTimeMillis());
|
||||
waypoint.setId(waypointId);
|
||||
ContentValues contentValues = contentProviderUtils.createContentValues(waypoint);
|
||||
Assert.assertEquals(waypointId.getId(), contentValues.get(WaypointsColumns._ID));
|
||||
Assert.assertEquals((int) (TestDataUtil.INITIAL_LONGITUDE * 1000000), contentValues.get(WaypointsColumns.LONGITUDE));
|
||||
Assert.assertEquals(TEST_DESC, contentValues.get(WaypointsColumns.DESCRIPTION));
|
||||
assertEquals(waypointId.getId(), contentValues.get(MarkerColumns._ID));
|
||||
assertEquals((int) (TestDataUtil.INITIAL_LONGITUDE * 1000000), contentValues.get(MarkerColumns.LONGITUDE));
|
||||
assertEquals(TEST_DESC, contentValues.get(MarkerColumns.DESCRIPTION));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#createWaypoint(Cursor)}.
|
||||
* Tests the method {@link ContentProviderUtils#createMarker(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++);
|
||||
when(cursorMock.getColumnIndexOrThrow(MarkerColumns._ID)).thenReturn(columnIndex++);
|
||||
when(cursorMock.getColumnIndexOrThrow(MarkerColumns.NAME)).thenReturn(columnIndex++);
|
||||
when(cursorMock.getColumnIndexOrThrow(MarkerColumns.TRACKID)).thenReturn(columnIndex++);
|
||||
columnIndex = startColumnIndex;
|
||||
// Id
|
||||
when(cursorMock.isNull(columnIndex++)).thenReturn(false);
|
||||
@@ -501,15 +505,15 @@ public class CustomContentProviderUtilsTest {
|
||||
long trackId = 11L;
|
||||
when(cursorMock.getLong(columnIndex++)).thenReturn(trackId);
|
||||
|
||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursorMock);
|
||||
Assert.assertEquals(id, waypoint.getId().getId());
|
||||
Assert.assertEquals(name, waypoint.getName());
|
||||
Assert.assertEquals(trackId, waypoint.getTrackId().getId());
|
||||
Marker waypoint = contentProviderUtils.createMarker(cursorMock);
|
||||
assertEquals(id, waypoint.getId().getId());
|
||||
assertEquals(name, waypoint.getName());
|
||||
assertEquals(trackId, waypoint.getTrackId().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method
|
||||
* {@link ContentProviderUtils#deleteWaypoint(Context, Waypoint.Id)}
|
||||
* {@link ContentProviderUtils#deleteMarker(Context, Marker.Id)}
|
||||
* when there is only one waypoint in the track.
|
||||
*/
|
||||
@Test
|
||||
@@ -518,26 +522,26 @@ public class CustomContentProviderUtilsTest {
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||
|
||||
// Insert at first.
|
||||
Waypoint waypoint1 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint1 = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint1.setDescription(TEST_DESC);
|
||||
waypoint1.setTrackId(trackId);
|
||||
contentProviderUtils.insertWaypoint(waypoint1);
|
||||
contentProviderUtils.insertMarker(waypoint1);
|
||||
|
||||
// Check insert was done.
|
||||
Assert.assertEquals(contentProviderUtils.getWaypointCount(trackId), 1);
|
||||
assertEquals(contentProviderUtils.getMarkerCount(trackId), 1);
|
||||
|
||||
// Get waypoint id that needs to delete.
|
||||
Waypoint.Id waypoint1Id = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1)));
|
||||
Marker.Id waypoint1Id = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint1)));
|
||||
|
||||
// Delete
|
||||
contentProviderUtils.deleteWaypoint(context, waypoint1Id);
|
||||
contentProviderUtils.deleteMarker(context, waypoint1Id);
|
||||
|
||||
Assert.assertNull(contentProviderUtils.getWaypoint(waypoint1Id));
|
||||
assertNull(contentProviderUtils.getMarker(waypoint1Id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method
|
||||
* {@link ContentProviderUtils#deleteWaypoint(Context, Waypoint.Id)}
|
||||
* {@link ContentProviderUtils#deleteMarker(Context, Marker.Id)}
|
||||
* when there is only one waypoint in the track.
|
||||
*/
|
||||
@Test
|
||||
@@ -547,32 +551,32 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// Insert at first.
|
||||
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
||||
Waypoint waypoint1 = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
contentProviderUtils.insertWaypoint(waypoint1);
|
||||
Marker waypoint1 = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
contentProviderUtils.insertMarker(waypoint1);
|
||||
|
||||
// Check insert was done.
|
||||
Assert.assertEquals(contentProviderUtils.getWaypointCount(trackId), 1);
|
||||
assertEquals(contentProviderUtils.getMarkerCount(trackId), 1);
|
||||
|
||||
// Get waypoint id that needs to delete.
|
||||
Waypoint.Id waypoint1Id = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1)));
|
||||
Marker.Id waypoint1Id = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint1)));
|
||||
|
||||
// Check waypoint has photo and it's in the external storage.
|
||||
Assert.assertTrue(waypoint1.hasPhoto());
|
||||
assertTrue(waypoint1.hasPhoto());
|
||||
File dir = FileUtils.getPhotoDir(context, trackId);
|
||||
Assert.assertTrue(dir.isDirectory());
|
||||
Assert.assertEquals(1, dir.list().length);
|
||||
Assert.assertTrue(dir.exists());
|
||||
assertTrue(dir.isDirectory());
|
||||
assertEquals(1, dir.list().length);
|
||||
assertTrue(dir.exists());
|
||||
|
||||
// Delete
|
||||
contentProviderUtils.deleteWaypoint(context, waypoint1Id);
|
||||
contentProviderUtils.deleteMarker(context, waypoint1Id);
|
||||
|
||||
// Check waypoint doesn't exists and photo folder was deleted.
|
||||
Assert.assertNull(contentProviderUtils.getWaypoint(waypoint1Id));
|
||||
Assert.assertFalse(dir.exists());
|
||||
assertNull(contentProviderUtils.getMarker(waypoint1Id));
|
||||
assertFalse(dir.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#deleteWaypoint(Context, Waypoint.Id)} when there is more than one waypoint in the track.
|
||||
* Tests the method {@link ContentProviderUtils#deleteMarker(Context, Marker.Id)} when there is more than one waypoint in the track.
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteWaypoint_hasNextWayPoint() {
|
||||
@@ -596,67 +600,67 @@ public class CustomContentProviderUtilsTest {
|
||||
// TestDataUtil.insertTrackWithLocations(contentProviderUtils, track);
|
||||
|
||||
// Insert at first.
|
||||
Waypoint waypoint1 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint1 = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint1.setDescription(MOCK_DESC);
|
||||
waypoint1.setTrackId(trackId);
|
||||
Waypoint.Id waypoint1Id = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1)));
|
||||
Marker.Id waypoint1Id = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint1)));
|
||||
|
||||
Waypoint waypoint2 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint2 = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint2.setDescription(MOCK_DESC);
|
||||
waypoint2.setTrackId(trackId);
|
||||
Waypoint.Id waypoint2Id = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint2)));
|
||||
Marker.Id waypoint2Id = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint2)));
|
||||
|
||||
// Delete
|
||||
Assert.assertNotNull(contentProviderUtils.getWaypoint(waypoint1Id));
|
||||
contentProviderUtils.deleteWaypoint(context, waypoint1Id);
|
||||
Assert.assertNull(contentProviderUtils.getWaypoint(waypoint1Id));
|
||||
assertNotNull(contentProviderUtils.getMarker(waypoint1Id));
|
||||
contentProviderUtils.deleteMarker(context, waypoint1Id);
|
||||
assertNull(contentProviderUtils.getMarker(waypoint1Id));
|
||||
|
||||
Assert.assertEquals(MOCK_DESC, contentProviderUtils.getWaypoint(waypoint2Id).getDescription());
|
||||
assertEquals(MOCK_DESC, contentProviderUtils.getMarker(waypoint2Id).getDescription());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#getNextWaypointNumber(Track.Id)}.
|
||||
* Tests the method {@link ContentProviderUtils#getNextMarkerNumber(Track.Id)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetNextWaypointNumber() {
|
||||
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||
|
||||
Waypoint waypoint1 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint1 = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint1.setTrackId(trackId);
|
||||
Waypoint waypoint2 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint2 = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint2.setTrackId(trackId);
|
||||
Waypoint waypoint3 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint3 = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint3.setTrackId(trackId);
|
||||
Waypoint waypoint4 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint4 = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint4.setTrackId(trackId);
|
||||
contentProviderUtils.insertWaypoint(waypoint1);
|
||||
contentProviderUtils.insertWaypoint(waypoint2);
|
||||
contentProviderUtils.insertWaypoint(waypoint3);
|
||||
contentProviderUtils.insertWaypoint(waypoint4);
|
||||
contentProviderUtils.insertMarker(waypoint1);
|
||||
contentProviderUtils.insertMarker(waypoint2);
|
||||
contentProviderUtils.insertMarker(waypoint3);
|
||||
contentProviderUtils.insertMarker(waypoint4);
|
||||
|
||||
Assert.assertEquals(4, contentProviderUtils.getNextWaypointNumber(trackId));
|
||||
assertEquals(4, contentProviderUtils.getNextMarkerNumber(trackId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#insertWaypoint(Waypoint)} and
|
||||
* {@link ContentProviderUtils#getWaypoint(Waypoint.Id)}.
|
||||
* Tests the method {@link ContentProviderUtils#insertMarker(Marker)} and
|
||||
* {@link ContentProviderUtils#getMarker(Marker.Id)}.
|
||||
*/
|
||||
@Test
|
||||
public void testInsertAndGetWaypoint() {
|
||||
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||
|
||||
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint.setDescription(TEST_DESC);
|
||||
waypoint.setTrackId(trackId);
|
||||
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||
Marker.Id waypointId = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint)));
|
||||
|
||||
Assert.assertEquals(TEST_DESC, contentProviderUtils.getWaypoint(waypointId).getDescription());
|
||||
assertEquals(TEST_DESC, contentProviderUtils.getMarker(waypointId).getDescription());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#updateWaypoint(Context, Waypoint)}.
|
||||
* Tests the method {@link ContentProviderUtils#updateMarker(Context, Marker)}.
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateWaypoint() {
|
||||
@@ -664,21 +668,21 @@ public class CustomContentProviderUtilsTest {
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||
|
||||
// Insert at first.
|
||||
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
Marker waypoint = new Marker(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||
waypoint.setDescription(TEST_DESC);
|
||||
waypoint.setTrackId(trackId);
|
||||
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||
Marker.Id waypointId = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint)));
|
||||
|
||||
// Update
|
||||
waypoint = contentProviderUtils.getWaypoint(waypointId);
|
||||
waypoint = contentProviderUtils.getMarker(waypointId);
|
||||
waypoint.setDescription(TEST_DESC_NEW);
|
||||
contentProviderUtils.updateWaypoint(context, waypoint);
|
||||
contentProviderUtils.updateMarker(context, waypoint);
|
||||
|
||||
Assert.assertEquals(TEST_DESC_NEW, contentProviderUtils.getWaypoint(waypointId).getDescription());
|
||||
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(waypointId).getDescription());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#updateWaypoint(Context, Waypoint)}.
|
||||
* Tests the method {@link ContentProviderUtils#updateMarker(Context, Marker)}.
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateWaypoint_withPhoto() throws IOException {
|
||||
@@ -689,32 +693,32 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// Insert at first.
|
||||
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
||||
Waypoint waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
Marker waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
waypoint.setDescription(TEST_DESC);
|
||||
waypoint.setTrackId(trackId);
|
||||
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||
Marker.Id waypointId = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint)));
|
||||
|
||||
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId.getId());
|
||||
Assert.assertTrue(dir.exists());
|
||||
Assert.assertTrue(dir.isDirectory());
|
||||
Assert.assertEquals(1, dir.list().length);
|
||||
assertTrue(dir.exists());
|
||||
assertTrue(dir.isDirectory());
|
||||
assertEquals(1, dir.list().length);
|
||||
|
||||
// Update
|
||||
waypoint = contentProviderUtils.getWaypoint(waypointId);
|
||||
waypoint = contentProviderUtils.getMarker(waypointId);
|
||||
waypoint.setName(TEST_NAME_NEW);
|
||||
waypoint.setDescription(TEST_DESC_NEW);
|
||||
contentProviderUtils.updateWaypoint(context, waypoint);
|
||||
contentProviderUtils.updateMarker(context, waypoint);
|
||||
|
||||
Assert.assertEquals(TEST_NAME_NEW, contentProviderUtils.getWaypoint(waypointId).getName());
|
||||
Assert.assertEquals(TEST_DESC_NEW, contentProviderUtils.getWaypoint(waypointId).getDescription());
|
||||
Assert.assertTrue(waypoint.hasPhoto());
|
||||
Assert.assertTrue(dir.exists());
|
||||
Assert.assertTrue(dir.isDirectory());
|
||||
Assert.assertEquals(1, dir.list().length);
|
||||
assertEquals(TEST_NAME_NEW, contentProviderUtils.getMarker(waypointId).getName());
|
||||
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(waypointId).getDescription());
|
||||
assertTrue(waypoint.hasPhoto());
|
||||
assertTrue(dir.exists());
|
||||
assertTrue(dir.isDirectory());
|
||||
assertEquals(1, dir.list().length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#updateWaypoint(Context, Waypoint)}.
|
||||
* Tests the method {@link ContentProviderUtils#updateMarker(Context, Marker)}.
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateWaypoint_delPhotoAndDir() throws IOException {
|
||||
@@ -725,31 +729,31 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// Insert at first.
|
||||
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
||||
Waypoint waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
Marker waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
waypoint.setDescription(TEST_DESC);
|
||||
waypoint.setTrackId(trackId);
|
||||
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||
Marker.Id waypointId = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint)));
|
||||
|
||||
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId.getId());
|
||||
Assert.assertTrue(dir.exists());
|
||||
Assert.assertTrue(dir.isDirectory());
|
||||
Assert.assertEquals(1, dir.list().length);
|
||||
assertTrue(dir.exists());
|
||||
assertTrue(dir.isDirectory());
|
||||
assertEquals(1, dir.list().length);
|
||||
|
||||
// Update
|
||||
waypoint = contentProviderUtils.getWaypoint(waypointId);
|
||||
waypoint = contentProviderUtils.getMarker(waypointId);
|
||||
waypoint.setName(TEST_NAME_NEW);
|
||||
waypoint.setDescription(TEST_DESC_NEW);
|
||||
waypoint.setPhotoUrl(null);
|
||||
contentProviderUtils.updateWaypoint(context, waypoint);
|
||||
contentProviderUtils.updateMarker(context, waypoint);
|
||||
|
||||
Assert.assertEquals(TEST_NAME_NEW, contentProviderUtils.getWaypoint(waypointId).getName());
|
||||
Assert.assertEquals(TEST_DESC_NEW, contentProviderUtils.getWaypoint(waypointId).getDescription());
|
||||
Assert.assertFalse(waypoint.hasPhoto());
|
||||
Assert.assertFalse(dir.exists());
|
||||
assertEquals(TEST_NAME_NEW, contentProviderUtils.getMarker(waypointId).getName());
|
||||
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(waypointId).getDescription());
|
||||
assertFalse(waypoint.hasPhoto());
|
||||
assertFalse(dir.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the method {@link ContentProviderUtils#updateWaypoint(Context, Waypoint)}.
|
||||
* Tests the method {@link ContentProviderUtils#updateMarker(Context, Marker)}.
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateWaypoint_delPhotoNotDir() throws IOException {
|
||||
@@ -760,30 +764,30 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// Insert two waypoints with photos.
|
||||
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
||||
Waypoint waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
Marker waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
waypoint.setDescription(TEST_DESC);
|
||||
waypoint.setTrackId(trackId);
|
||||
Waypoint otherWaypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
Marker otherWaypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||
otherWaypoint.setDescription(TEST_DESC);
|
||||
otherWaypoint.setTrackId(trackId);
|
||||
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||
contentProviderUtils.insertWaypoint(otherWaypoint);
|
||||
Marker.Id waypointId = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(waypoint)));
|
||||
contentProviderUtils.insertMarker(otherWaypoint);
|
||||
|
||||
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId.getId());
|
||||
Assert.assertTrue(dir.exists());
|
||||
Assert.assertTrue(dir.isDirectory());
|
||||
Assert.assertEquals(2, dir.list().length);
|
||||
assertTrue(dir.exists());
|
||||
assertTrue(dir.isDirectory());
|
||||
assertEquals(2, dir.list().length);
|
||||
|
||||
// Update one waypoint deleting photo.
|
||||
waypoint = contentProviderUtils.getWaypoint(waypointId);
|
||||
waypoint = contentProviderUtils.getMarker(waypointId);
|
||||
waypoint.setPhotoUrl(null);
|
||||
contentProviderUtils.updateWaypoint(context, waypoint);
|
||||
contentProviderUtils.updateMarker(context, waypoint);
|
||||
|
||||
Assert.assertEquals(TEST_DESC, contentProviderUtils.getWaypoint(waypointId).getDescription());
|
||||
Assert.assertFalse(waypoint.hasPhoto());
|
||||
Assert.assertTrue(dir.exists());
|
||||
Assert.assertTrue(dir.isDirectory());
|
||||
Assert.assertEquals(1, dir.list().length);
|
||||
assertEquals(TEST_DESC, contentProviderUtils.getMarker(waypointId).getDescription());
|
||||
assertFalse(waypoint.hasPhoto());
|
||||
assertTrue(dir.exists());
|
||||
assertTrue(dir.isDirectory());
|
||||
assertEquals(1, dir.list().length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -798,9 +802,9 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// when / then
|
||||
contentProviderUtils.bulkInsertTrackPoint(track.second, trackId);
|
||||
Assert.assertEquals(20, contentProviderUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
|
||||
assertEquals(20, contentProviderUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
|
||||
contentProviderUtils.bulkInsertTrackPoint(Arrays.copyOfRange(track.second, 0, 8), trackId);
|
||||
Assert.assertEquals(28, contentProviderUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
|
||||
assertEquals(28, contentProviderUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -839,11 +843,11 @@ public class CustomContentProviderUtilsTest {
|
||||
TrackPoint trackPoint = contentProviderUtils.createTrackPoint(cursorMock);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(longitude, trackPoint.getLongitude(), 0.01);
|
||||
Assert.assertEquals(latitude, trackPoint.getLatitude(), 0.01);
|
||||
Assert.assertEquals(time, trackPoint.getTime(), 0.01);
|
||||
Assert.assertEquals(speed, trackPoint.getSpeed(), 0.01);
|
||||
Assert.assertFalse(trackPoint.hasHeartRate());
|
||||
assertEquals(longitude, trackPoint.getLongitude(), 0.01);
|
||||
assertEquals(latitude, trackPoint.getLatitude(), 0.01);
|
||||
assertEquals(time, trackPoint.getTime(), 0.01);
|
||||
assertEquals(speed, trackPoint.getSpeed(), 0.01);
|
||||
assertFalse(trackPoint.hasHeartRate());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -857,7 +861,7 @@ public class CustomContentProviderUtilsTest {
|
||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||
|
||||
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
|
||||
Assert.assertEquals(11, contentProviderUtils.getTrackPoints(trackId).size());
|
||||
assertEquals(11, contentProviderUtils.getTrackPoints(trackId).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -876,10 +880,10 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// then
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertTrue(trackPoints.get(10).hasHeartRate());
|
||||
Assert.assertEquals(trackPoint.getHeartRate_bpm(), trackPoints.get(10).getHeartRate_bpm(), 0.01);
|
||||
Assert.assertEquals(trackPoint.getCyclingCadence_rpm(), trackPoints.get(10).getCyclingCadence_rpm(), 0.01);
|
||||
Assert.assertEquals(trackPoint.getPower(), trackPoints.get(10).getPower(), 0.01);
|
||||
assertTrue(trackPoints.get(10).hasHeartRate());
|
||||
assertEquals(trackPoint.getHeartRate_bpm(), trackPoints.get(10).getHeartRate_bpm(), 0.01);
|
||||
assertEquals(trackPoint.getCyclingCadence_rpm(), trackPoints.get(10).getCyclingCadence_rpm(), 0.01);
|
||||
assertEquals(trackPoint.getPower(), trackPoints.get(10).getPower(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -914,7 +918,7 @@ public class CustomContentProviderUtilsTest {
|
||||
Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds[1], 5, true);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(2, cursor.getCount());
|
||||
assertEquals(2, cursor.getCount());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -936,7 +940,7 @@ public class CustomContentProviderUtilsTest {
|
||||
Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds[8], 5, false);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(2, cursor.getCount());
|
||||
assertEquals(2, cursor.getCount());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -960,12 +964,12 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// then
|
||||
for (int i = 0; i < trackpointIds.length; i++) {
|
||||
Assert.assertTrue(trackPointIterator.hasNext());
|
||||
assertTrue(trackPointIterator.hasNext());
|
||||
TrackPoint trackPoint = trackPointIterator.next();
|
||||
Assert.assertEquals(startTrackPointId - i, trackPointIterator.getTrackPointId());
|
||||
assertEquals(startTrackPointId - i, trackPointIterator.getTrackPointId());
|
||||
checkLocation((trackpointIds.length - 1) - i, trackPoint.getLocation());
|
||||
}
|
||||
Assert.assertFalse(trackPointIterator.hasNext());
|
||||
assertFalse(trackPointIterator.hasNext());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -990,13 +994,13 @@ public class CustomContentProviderUtilsTest {
|
||||
|
||||
// then
|
||||
for (int i = 0; i < trackpointIds.length; i++) {
|
||||
Assert.assertTrue(trackPointIterator.hasNext());
|
||||
assertTrue(trackPointIterator.hasNext());
|
||||
TrackPoint trackPoint = trackPointIterator.next();
|
||||
Assert.assertEquals(startTrackPointId + i, trackPointIterator.getTrackPointId());
|
||||
assertEquals(startTrackPointId + i, trackPointIterator.getTrackPointId());
|
||||
|
||||
checkLocation(i, trackPoint.getLocation());
|
||||
}
|
||||
Assert.assertFalse(trackPointIterator.hasNext());
|
||||
assertFalse(trackPointIterator.hasNext());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1006,16 +1010,16 @@ public class CustomContentProviderUtilsTest {
|
||||
* @param location the location to be checked
|
||||
*/
|
||||
private void checkLocation(int i, Location location) {
|
||||
Assert.assertEquals(TestDataUtil.INITIAL_LATITUDE + (double) i / 10000.0, location.getLatitude(), 0.01);
|
||||
Assert.assertEquals(TestDataUtil.INITIAL_LONGITUDE - (double) i / 10000.0, location.getLongitude(), 0.01);
|
||||
Assert.assertEquals((float) i / 100.0f, location.getAccuracy(), 0.01);
|
||||
Assert.assertEquals(i * TestDataUtil.ALTITUDE_INTERVAL, location.getAltitude(), 0.01);
|
||||
assertEquals(TestDataUtil.INITIAL_LATITUDE + (double) i / 10000.0, location.getLatitude(), 0.01);
|
||||
assertEquals(TestDataUtil.INITIAL_LONGITUDE - (double) i / 10000.0, location.getLongitude(), 0.01);
|
||||
assertEquals((float) i / 100.0f, location.getAccuracy(), 0.01);
|
||||
assertEquals(i * TestDataUtil.ALTITUDE_INTERVAL, location.getAltitude(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatIdListForUri() {
|
||||
Assert.assertEquals("", ContentProviderUtils.formatIdListForUri());
|
||||
Assert.assertEquals("12", ContentProviderUtils.formatIdListForUri(new Track.Id(12)));
|
||||
Assert.assertEquals("42,43,44", ContentProviderUtils.formatIdListForUri(new Track.Id(42), new Track.Id(43), new Track.Id(44)));
|
||||
assertEquals("", ContentProviderUtils.formatIdListForUri());
|
||||
assertEquals("12", ContentProviderUtils.formatIdListForUri(new Track.Id(12)));
|
||||
assertEquals("42,43,44", ContentProviderUtils.formatIdListForUri(new Track.Id(42), new Track.Id(43), new Track.Id(44)));
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -18,9 +18,9 @@ import org.junit.runner.RunWith;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -45,7 +45,7 @@ public class CustomSQLiteOpenHelperTest {
|
||||
@VisibleForTesting
|
||||
public static Map<String, String> getTableSQL(SQLiteDatabase db) {
|
||||
HashMap<String, String> tableSQL = new HashMap<>();
|
||||
try (Cursor cursor = db.query("sqlite_master", new String[]{"name", "SQL"}, "name IN ('" + TracksColumns.TABLE_NAME + "', '" + TrackPointsColumns.TABLE_NAME + "', '" + WaypointsColumns.TABLE_NAME + "')", null, null, null, "name")) {
|
||||
try (Cursor cursor = db.query("sqlite_master", new String[]{"name", "SQL"}, "name IN ('" + TracksColumns.TABLE_NAME + "', '" + TrackPointsColumns.TABLE_NAME + "', '" + MarkerColumns.TABLE_NAME + "')", null, null, null, "name")) {
|
||||
if (cursor != null) {
|
||||
while (cursor.moveToNext()) {
|
||||
tableSQL.put(cursor.getString(0), cursor.getString(1));
|
||||
@@ -106,8 +106,8 @@ public class CustomSQLiteOpenHelperTest {
|
||||
assertTrue(hasSqlCreate(db, TrackPointsColumns.CREATE_TABLE));
|
||||
assertTrue(hasSqlCreate(db, TrackPointsColumns.CREATE_TABLE_INDEX));
|
||||
|
||||
assertTrue(hasSqlCreate(db, WaypointsColumns.CREATE_TABLE));
|
||||
assertTrue(hasSqlCreate(db, WaypointsColumns.CREATE_TABLE_INDEX));
|
||||
assertTrue(hasSqlCreate(db, MarkerColumns.CREATE_TABLE));
|
||||
assertTrue(hasSqlCreate(db, MarkerColumns.CREATE_TABLE_INDEX));
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
@@ -140,13 +140,13 @@ public class CustomSQLiteOpenHelperTest {
|
||||
|
||||
assertEquals(tablesByCreate.get(TracksColumns.TABLE_NAME), tableByUpgrade.get(TracksColumns.TABLE_NAME));
|
||||
assertEquals(tablesByCreate.get(TrackPointsColumns.TABLE_NAME), tableByUpgrade.get(TrackPointsColumns.TABLE_NAME));
|
||||
assertEquals(tablesByCreate.get(WaypointsColumns.TABLE_NAME), tableByUpgrade.get(WaypointsColumns.TABLE_NAME));
|
||||
assertEquals(tablesByCreate.get(MarkerColumns.TABLE_NAME), tableByUpgrade.get(MarkerColumns.TABLE_NAME));
|
||||
|
||||
// then - verify custom indices
|
||||
assertEquals(3, indicesByCreate.size());
|
||||
assertEquals(indicesByUpgrade.get(TracksColumns.TABLE_NAME), indicesByCreate.get(TracksColumns.TABLE_NAME));
|
||||
assertEquals(indicesByUpgrade.get(TrackPointsColumns.TABLE_NAME), indicesByCreate.get(TrackPointsColumns.TABLE_NAME));
|
||||
assertEquals(indicesByUpgrade.get(WaypointsColumns.TABLE_NAME), indicesByCreate.get(WaypointsColumns.TABLE_NAME));
|
||||
assertEquals(indicesByUpgrade.get(MarkerColumns.TABLE_NAME), indicesByCreate.get(MarkerColumns.TABLE_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+7
-6
@@ -3,7 +3,6 @@ package de.dennisguse.opentracks.content.provider;
|
||||
import android.net.Uri;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -12,17 +11,19 @@ import java.util.Set;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class ShareContentProviderTest {
|
||||
|
||||
@Test
|
||||
public void testCreateandParseURI_invalid() {
|
||||
public void testCreateAndParseURI_invalid() {
|
||||
Uri uri = Uri.parse("content://de.dennisguse.opentracks.debug.content/tracks/1");
|
||||
|
||||
Assert.assertEquals(0, ShareContentProvider.parseURI(uri).size());
|
||||
assertEquals(0, ShareContentProvider.parseURI(uri).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateandParseURI_valid() {
|
||||
public void testCreateAndParseURI_valid() {
|
||||
Set<Track.Id> trackIds = new HashSet<>();
|
||||
trackIds.add(new Track.Id(1));
|
||||
trackIds.add(new Track.Id(3));
|
||||
@@ -30,7 +31,7 @@ public class ShareContentProviderTest {
|
||||
|
||||
Pair<Uri, String> shareURIandMIME = ShareContentProvider.createURI(trackIds, "TrackName", TrackFileFormat.KML_ONLY_TRACK);
|
||||
|
||||
Assert.assertEquals(trackIds, ShareContentProvider.parseURI(shareURIandMIME.first));
|
||||
assertEquals(trackIds, ShareContentProvider.parseURI(shareURIandMIME.first));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -39,6 +40,6 @@ public class ShareContentProviderTest {
|
||||
trackIds.add(new Track.Id(1));
|
||||
Pair<Uri, String> shareURIandMIME = ShareContentProvider.createURI(trackIds, "../../&1=1", TrackFileFormat.KML_ONLY_TRACK);
|
||||
|
||||
Assert.assertEquals(Uri.parse("content://de.dennisguse.opentracks.debug.content/tracks/kml_only_track/1/..%2F..%2F%261%3D1.kml"), shareURIandMIME.first);
|
||||
assertEquals(Uri.parse("content://de.dennisguse.opentracks.debug.content/tracks/kml_only_track/1/..%2F..%2F%261%3D1.kml"), shareURIandMIME.first);
|
||||
}
|
||||
}
|
||||
+11
-9
@@ -2,12 +2,14 @@ package de.dennisguse.opentracks.content.sensor;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import de.dennisguse.opentracks.util.UintUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SensorDataCyclingTest {
|
||||
|
||||
@@ -21,7 +23,7 @@ public class SensorDataCyclingTest {
|
||||
current.compute(previous);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||
assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -34,7 +36,7 @@ public class SensorDataCyclingTest {
|
||||
current.compute(previous);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(33.53, current.getCadence_rpm(), 0.01);
|
||||
assertEquals(33.53, current.getCadence_rpm(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -47,7 +49,7 @@ public class SensorDataCyclingTest {
|
||||
current.compute(previous);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(0, current.getCadence_rpm(), 0.01);
|
||||
assertEquals(0, current.getCadence_rpm(), 0.01);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +63,7 @@ public class SensorDataCyclingTest {
|
||||
current.compute(previous);
|
||||
|
||||
// then
|
||||
Assert.assertFalse(current.hasCadence_rpm());
|
||||
assertFalse(current.hasCadence_rpm());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -74,7 +76,7 @@ public class SensorDataCyclingTest {
|
||||
current.compute(previous);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||
assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -87,7 +89,7 @@ public class SensorDataCyclingTest {
|
||||
current.compute(previous);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||
assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,7 +102,7 @@ public class SensorDataCyclingTest {
|
||||
current.compute(previous, 2150);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(1.20, current.getSpeed_mps(), 0.01);
|
||||
assertEquals(1.20, current.getSpeed_mps(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,6 +115,6 @@ public class SensorDataCyclingTest {
|
||||
current.compute(previous, 2000);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(2, current.getSpeed_mps(), 0.01);
|
||||
assertEquals(2, current.getSpeed_mps(), 0.01);
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
@@ -35,6 +34,8 @@ import de.dennisguse.opentracks.chart.ChartView;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests {@link ChartFragment}.
|
||||
*
|
||||
@@ -78,9 +79,9 @@ public class ChartFragmentTest {
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(Float.NaN, point.getHeartRate(), 0.01);
|
||||
Assert.assertEquals(Float.NaN, point.getCadence(), 0.01);
|
||||
Assert.assertEquals(Float.NaN, point.getPower(), 0.01);
|
||||
assertEquals(Float.NaN, point.getHeartRate(), 0.01);
|
||||
assertEquals(Float.NaN, point.getCadence(), 0.01);
|
||||
assertEquals(Float.NaN, point.getPower(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,9 +99,9 @@ public class ChartFragmentTest {
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(100.0, point.getHeartRate(), 0.01);
|
||||
Assert.assertEquals(101.0, point.getCadence(), 0.01);
|
||||
Assert.assertEquals(102.0, point.getPower(), 0.01);
|
||||
assertEquals(100.0, point.getHeartRate(), 0.01);
|
||||
assertEquals(101.0, point.getCadence(), 0.01);
|
||||
assertEquals(102.0, point.getPower(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,12 +113,12 @@ public class ChartFragmentTest {
|
||||
// Resets last location and writes first location.
|
||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||
Assert.assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||
assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||
|
||||
// The second is a same location, just different time.
|
||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
Assert.assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||
assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||
|
||||
// The third location is a new location, and use metric.
|
||||
TrackPoint trackPoint3 = TrackStubUtils.createDefaultTrackPoint();
|
||||
@@ -129,7 +130,7 @@ public class ChartFragmentTest {
|
||||
Location.distanceBetween(trackPoint2.getLatitude(), trackPoint2.getLongitude(),
|
||||
trackPoint3.getLatitude(), trackPoint3.getLongitude(), results);
|
||||
double distance1 = results[0] * UnitConversions.M_TO_KM;
|
||||
Assert.assertEquals(distance1, point.getTimeOrDistance(), 0.01);
|
||||
assertEquals(distance1, point.getTimeOrDistance(), 0.01);
|
||||
|
||||
// The fourth location is a new location, and use metric.
|
||||
TrackPoint trackPoint4 = TrackStubUtils.createDefaultTrackPoint();
|
||||
@@ -140,7 +141,7 @@ public class ChartFragmentTest {
|
||||
Location.distanceBetween(trackPoint3.getLatitude(), trackPoint3.getLongitude(),
|
||||
trackPoint4.getLatitude(), trackPoint4.getLongitude(), results);
|
||||
double distance2 = results[0] * UnitConversions.M_TO_KM;
|
||||
Assert.assertEquals((distance1 + distance2), point.getTimeOrDistance(), 0.01);
|
||||
assertEquals((distance1 + distance2), point.getTimeOrDistance(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,7 +157,7 @@ public class ChartFragmentTest {
|
||||
// The first is a same location, just different time.
|
||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||
Assert.assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||
assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||
|
||||
// The second location is a new location, and use imperial.
|
||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||
@@ -170,7 +171,7 @@ public class ChartFragmentTest {
|
||||
float[] results = new float[4];
|
||||
Location.distanceBetween(trackPoint1.getLatitude(), trackPoint1.getLongitude(), trackPoint2.getLatitude(), trackPoint2.getLongitude(), results);
|
||||
double distance1 = results[0] * UnitConversions.M_TO_KM * UnitConversions.KM_TO_MI;
|
||||
Assert.assertEquals(distance1, point.getTimeOrDistance(), 0.01);
|
||||
assertEquals(distance1, point.getTimeOrDistance(), 0.01);
|
||||
|
||||
// The third location is a new location, and use imperial.
|
||||
TrackPoint trackPoint3 = TrackStubUtils.createDefaultTrackPoint();
|
||||
@@ -183,7 +184,7 @@ public class ChartFragmentTest {
|
||||
*/
|
||||
Location.distanceBetween(trackPoint2.getLatitude(), trackPoint2.getLongitude(), trackPoint3.getLatitude(), trackPoint3.getLongitude(), results);
|
||||
double distance2 = results[0] * UnitConversions.M_TO_KM * UnitConversions.KM_TO_MI;
|
||||
Assert.assertEquals(distance1 + distance2, point.getTimeOrDistance(), 0.01);
|
||||
assertEquals(distance1 + distance2, point.getTimeOrDistance(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,12 +195,12 @@ public class ChartFragmentTest {
|
||||
chartFragment.setChartByDistance(false);
|
||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||
Assert.assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||
assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||
long timeSpan = 222;
|
||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||
trackPoint2.setTime(trackPoint1.getTime() + timeSpan);
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
Assert.assertEquals((double) timeSpan, point.getTimeOrDistance(), 0.01);
|
||||
assertEquals((double) timeSpan, point.getTimeOrDistance(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,7 +215,7 @@ public class ChartFragmentTest {
|
||||
* Then only one value INITIAL_ALTITUDE in buffer.
|
||||
*/
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||
Assert.assertEquals(TrackStubUtils.INITIAL_ALTITUDE, point.getElevation(), 0.01);
|
||||
assertEquals(TrackStubUtils.INITIAL_ALTITUDE, point.getElevation(), 0.01);
|
||||
|
||||
/*
|
||||
* Send another value to buffer, now there are two values, INITIAL_ALTITUDE and INITIAL_ALTITUDE * 2.
|
||||
@@ -222,7 +223,7 @@ public class ChartFragmentTest {
|
||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||
trackPoint2.setAltitude(TrackStubUtils.INITIAL_ALTITUDE * 2);
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
Assert.assertEquals((TrackStubUtils.INITIAL_ALTITUDE + TrackStubUtils.INITIAL_ALTITUDE * 2) / 2.0, point.getElevation(), 0.01);
|
||||
assertEquals((TrackStubUtils.INITIAL_ALTITUDE + TrackStubUtils.INITIAL_ALTITUDE * 2) / 2.0, point.getElevation(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +240,7 @@ public class ChartFragmentTest {
|
||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||
trackPoint1.setSpeed(128.5f);
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||
Assert.assertEquals(0.0, point.getSpeed(), 0.01);
|
||||
assertEquals(0.0, point.getSpeed(), 0.01);
|
||||
|
||||
/*
|
||||
* Tests the logic when both metricUnits and reportSpeed are true.
|
||||
@@ -253,7 +254,7 @@ public class ChartFragmentTest {
|
||||
trackPoint2.setTime(trackPoint1.getTime() + 222);
|
||||
trackPoint2.setSpeed(130);
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
Assert.assertEquals(130.0 * UnitConversions.MPS_TO_KMH, point.getSpeed(), 0.01);
|
||||
assertEquals(130.0 * UnitConversions.MPS_TO_KMH, point.getSpeed(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,7 +268,7 @@ public class ChartFragmentTest {
|
||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||
trackPoint1.setSpeed(100.0f);
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||
Assert.assertEquals(0.0, point.getSpeed(), 0.01);
|
||||
assertEquals(0.0, point.getSpeed(), 0.01);
|
||||
|
||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||
|
||||
@@ -278,7 +279,7 @@ public class ChartFragmentTest {
|
||||
trackPoint2.setTime(trackPoint2.getTime() + 222);
|
||||
trackPoint2.setSpeed(102);
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
Assert.assertEquals(102.0 * UnitConversions.MPS_TO_KMH * UnitConversions.KM_TO_MI, point.getSpeed(), 0.01);
|
||||
assertEquals(102.0 * UnitConversions.MPS_TO_KMH * UnitConversions.KM_TO_MI, point.getSpeed(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,7 +293,7 @@ public class ChartFragmentTest {
|
||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||
trackPoint1.setSpeed(100.0f);
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||
Assert.assertEquals(0.0, point.getSpeed(), 0.01);
|
||||
assertEquals(0.0, point.getSpeed(), 0.01);
|
||||
|
||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||
|
||||
@@ -303,7 +304,7 @@ public class ChartFragmentTest {
|
||||
trackPoint2.setTime(trackPoint2.getTime() + 222);
|
||||
trackPoint2.setSpeed(102);
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
Assert.assertEquals(HOURS_PER_UNIT / (102.0 * UnitConversions.MPS_TO_KMH), point.getPace(), 0.01);
|
||||
assertEquals(HOURS_PER_UNIT / (102.0 * UnitConversions.MPS_TO_KMH), point.getPace(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,6 +316,6 @@ public class ChartFragmentTest {
|
||||
TrackPoint trackPoint = TrackStubUtils.createDefaultTrackPoint();
|
||||
trackPoint.setSpeed(0);
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
||||
Assert.assertEquals(0.0, point.getPace(), 0.01);
|
||||
assertEquals(0.0, point.getPace(), 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -24,7 +24,6 @@ import android.net.Uri;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
|
||||
@@ -34,11 +33,12 @@ import java.util.Locale;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -70,7 +70,7 @@ public abstract class AbstractTestFileTrackImporter {
|
||||
static final long TRACK_POINT_ID_3 = 4;
|
||||
|
||||
private static final long WAYPOINT_ID_0 = 1;
|
||||
private static final Uri WAYPOINT_ID_O_URI = ContentUris.appendId(WaypointsColumns.CONTENT_URI.buildUpon(), WAYPOINT_ID_0).build();
|
||||
private static final Uri WAYPOINT_ID_O_URI = ContentUris.appendId(MarkerColumns.CONTENT_URI.buildUpon(), WAYPOINT_ID_0).build();
|
||||
|
||||
protected final Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
@@ -114,7 +114,7 @@ public abstract class AbstractTestFileTrackImporter {
|
||||
protected void expectTrackUpdate(ArgumentCaptor<Track> trackCaptor, boolean lastTrack, Track.Id trackId) {
|
||||
contentProviderUtils.updateTrack(trackCaptor.capture());
|
||||
|
||||
when(contentProviderUtils.insertWaypoint(any())).thenReturn(WAYPOINT_ID_O_URI);
|
||||
when(contentProviderUtils.insertMarker(any())).thenReturn(WAYPOINT_ID_O_URI);
|
||||
if (lastTrack) {
|
||||
// Return null to not add waypoints
|
||||
when(contentProviderUtils.getTrack(trackId)).thenReturn(null);
|
||||
@@ -122,10 +122,10 @@ public abstract class AbstractTestFileTrackImporter {
|
||||
}
|
||||
|
||||
protected void verifyTrack(Track track, String name, String description, long time) {
|
||||
Assert.assertEquals(name, track.getName());
|
||||
Assert.assertEquals(description, track.getDescription());
|
||||
assertEquals(name, track.getName());
|
||||
assertEquals(description, track.getDescription());
|
||||
if (time != -1L) {
|
||||
Assert.assertEquals(time, track.getTrackStatistics().getStartTime_ms());
|
||||
assertEquals(time, track.getTrackStatistics().getStartTime_ms());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+39
-36
@@ -21,10 +21,10 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
@@ -53,7 +53,7 @@ public class ExportImportTest {
|
||||
private static final String TRACK_CATEGORY = "the category";
|
||||
private static final String TRACK_DESCRIPTION = "the description";
|
||||
|
||||
private final List<Waypoint> waypoints = new ArrayList<>();
|
||||
private final List<Marker> markers = new ArrayList<>();
|
||||
private final List<TrackPoint> trackPoints = new ArrayList<>();
|
||||
|
||||
private Track.Id importTrackId;
|
||||
@@ -72,19 +72,19 @@ public class ExportImportTest {
|
||||
trackPoints.addAll(Arrays.asList(track.second));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Waypoint waypoint = new Waypoint(track.second[i].getLocation());
|
||||
waypoint.setName("the waypoint " + i);
|
||||
waypoint.setDescription("the waypoint description " + i);
|
||||
waypoint.setCategory("the waypoint category" + i);
|
||||
waypoint.setIcon("the waypoing icon" + i);
|
||||
waypoint.setPhotoUrl("the photo url" + i);
|
||||
waypoint.setTrackId(trackId);
|
||||
contentProviderUtils.insertWaypoint(waypoint);
|
||||
Marker marker = new Marker(track.second[i].getLocation());
|
||||
marker.setName("the marker " + i);
|
||||
marker.setDescription("the marker description " + i);
|
||||
marker.setCategory("the marker category" + i);
|
||||
marker.setIcon("the marker icon" + i);
|
||||
marker.setPhotoUrl("the photo url" + i);
|
||||
marker.setTrackId(trackId);
|
||||
contentProviderUtils.insertMarker(marker);
|
||||
|
||||
waypoints.add(waypoint);
|
||||
markers.add(marker);
|
||||
}
|
||||
|
||||
assertEquals(waypoints.size(), contentProviderUtils.getWaypointCount(trackId));
|
||||
assertEquals(markers.size(), contentProviderUtils.getMarkerCount(trackId));
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -129,11 +129,11 @@ public class ExportImportTest {
|
||||
assertEquals(track.getIcon(), importedTrack.getIcon());
|
||||
assertEquals(track.getUuid(), importedTrack.getUuid());
|
||||
|
||||
// 2. waypoints
|
||||
assertWaypoints();
|
||||
// 2. markers
|
||||
assertMarkers();
|
||||
|
||||
// 3. trackpoints
|
||||
assertTrackpoints(false, false, false);
|
||||
assertTrackpoints(false, false, false, false);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@@ -164,11 +164,11 @@ public class ExportImportTest {
|
||||
assertEquals(track.getName(), importedTrack.getName());
|
||||
assertEquals(track.getIcon(), importedTrack.getIcon());
|
||||
|
||||
// 2. waypoints
|
||||
assertWaypoints();
|
||||
// 2. markers
|
||||
assertMarkers();
|
||||
|
||||
// 3. trackpoints
|
||||
assertTrackpoints(true, true, true);
|
||||
assertTrackpoints(true, true, true, true);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@@ -253,11 +253,11 @@ public class ExportImportTest {
|
||||
//TODO exporting and importing a track icon is not yet supported by GpxTrackWriter.
|
||||
//assertEquals(track.getIcon(), trackImported.getIcon());
|
||||
|
||||
// 2. waypoints
|
||||
assertWaypoints();
|
||||
// 2. markers
|
||||
assertMarkers();
|
||||
|
||||
// 3. trackpoints
|
||||
assertTrackpoints(false, true, true);
|
||||
assertTrackpoints(false, true, true, false);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@@ -285,26 +285,26 @@ public class ExportImportTest {
|
||||
assertNull(trackImported);
|
||||
}
|
||||
|
||||
private void assertWaypoints() {
|
||||
assertEquals(waypoints.size(), contentProviderUtils.getWaypointCount(importTrackId));
|
||||
private void assertMarkers() {
|
||||
assertEquals(markers.size(), contentProviderUtils.getMarkerCount(importTrackId));
|
||||
|
||||
List<Waypoint> importedWaypoints = contentProviderUtils.getWaypoints(importTrackId);
|
||||
for (int i = 0; i < waypoints.size(); i++) {
|
||||
Waypoint waypoint = waypoints.get(i);
|
||||
Waypoint importedWaypoint = importedWaypoints.get(i);
|
||||
assertEquals(waypoint.getCategory(), importedWaypoint.getCategory());
|
||||
assertEquals(waypoint.getDescription(), importedWaypoint.getDescription());
|
||||
// assertEquals(waypoint.getIcon(), importedWaypoint.getIcon()); // TODO for KML
|
||||
assertEquals(waypoint.getName(), importedWaypoint.getName());
|
||||
assertEquals("", importedWaypoint.getPhotoUrl());
|
||||
List<Marker> importedMarkers = contentProviderUtils.getMarkers(importTrackId);
|
||||
for (int i = 0; i < markers.size(); i++) {
|
||||
Marker marker = markers.get(i);
|
||||
Marker importMarker = importedMarkers.get(i);
|
||||
assertEquals(marker.getCategory(), importMarker.getCategory());
|
||||
assertEquals(marker.getDescription(), importMarker.getDescription());
|
||||
// assertEquals(marker.getIcon(), importMarker.getIcon()); // TODO for KML
|
||||
assertEquals(marker.getName(), importMarker.getName());
|
||||
assertEquals("", importMarker.getPhotoUrl());
|
||||
|
||||
assertEquals(waypoint.getLocation().getLatitude(), importedWaypoint.getLocation().getLatitude(), 0.001);
|
||||
assertEquals(waypoint.getLocation().getLongitude(), importedWaypoint.getLocation().getLongitude(), 0.001);
|
||||
assertEquals(waypoint.getLocation().getAltitude(), importedWaypoint.getLocation().getAltitude(), 0.001);
|
||||
assertEquals(marker.getLocation().getLatitude(), importMarker.getLocation().getLatitude(), 0.001);
|
||||
assertEquals(marker.getLocation().getLongitude(), importMarker.getLocation().getLongitude(), 0.001);
|
||||
assertEquals(marker.getLocation().getAltitude(), importMarker.getLocation().getAltitude(), 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertTrackpoints(boolean verifyPower, boolean verifyHeartrate, boolean verifyCadence) {
|
||||
private void assertTrackpoints(boolean verifyPower, boolean verifyHeartrate, boolean verifyCadence, boolean verifyElevationGain) {
|
||||
List<TrackPoint> importedTrackPoints = contentProviderUtils.getTrackPoints(importTrackId);
|
||||
assertEquals(trackPoints.size(), importedTrackPoints.size());
|
||||
|
||||
@@ -330,6 +330,9 @@ public class ExportImportTest {
|
||||
if (verifyPower) {
|
||||
assertEquals(trackPoint.getPower(), importedTrackPoint.getPower(), 0.01);
|
||||
}
|
||||
if (verifyElevationGain) {
|
||||
assertEquals(trackPoint.getElevationGain(), importedTrackPoint.getElevationGain(), 0.01);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package de.dennisguse.opentracks.services;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -23,6 +22,8 @@ import org.junit.runners.JUnit4;
|
||||
|
||||
import de.dennisguse.opentracks.services.handlers.AdaptiveLocationListenerPolicy;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests the {@link AdaptiveLocationListenerPolicy}.
|
||||
*
|
||||
@@ -57,17 +58,17 @@ public class AdaptiveLocationListenerPolicyTest {
|
||||
@Test
|
||||
public void testGetDesiredPollingInterval() {
|
||||
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_BIG);
|
||||
Assert.assertEquals(MAX, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||
assertEquals(MAX, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||
|
||||
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_NORMAL);
|
||||
// First get the half of NEW_IDLE_TIME_NORMAL, and then round it to the nearest second.
|
||||
Assert.assertEquals((NEW_IDLE_TIME_NORMAL / 2 / 1000) * 1000, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||
assertEquals((NEW_IDLE_TIME_NORMAL / 2 / 1000) * 1000, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||
|
||||
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_SMALL);
|
||||
Assert.assertEquals(MIN, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||
assertEquals(MIN, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||
|
||||
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_LESS_THAN_MIN);
|
||||
Assert.assertEquals(MIN, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||
assertEquals(MIN, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,6 +76,6 @@ public class AdaptiveLocationListenerPolicyTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetMinDistance() {
|
||||
Assert.assertEquals(MIN_DISTANCE, adaptiveLocationListenerPolicy.getMinDistance_m());
|
||||
assertEquals(MIN_DISTANCE, adaptiveLocationListenerPolicy.getMinDistance_m());
|
||||
}
|
||||
}
|
||||
|
||||
+54
-48
@@ -25,16 +25,15 @@ import android.os.Looper;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.FlakyTest;
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.rule.GrantPermissionRule;
|
||||
import androidx.test.rule.ServiceTestRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -45,15 +44,22 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for the track recording service.
|
||||
*
|
||||
@@ -120,14 +126,14 @@ public class TrackRecordingServiceTest {
|
||||
@Test
|
||||
public void testStartable() throws TimeoutException {
|
||||
mServiceRule.startService(createStartIntent(context));
|
||||
Assert.assertNotNull(mServiceRule.bindService(createStartIntent(context)));
|
||||
assertNotNull(mServiceRule.bindService(createStartIntent(context)));
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@Test
|
||||
public void testBindable() throws TimeoutException {
|
||||
IBinder service = mServiceRule.bindService(createStartIntent(context));
|
||||
Assert.assertNotNull(service);
|
||||
assertNotNull(service);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -135,7 +141,7 @@ public class TrackRecordingServiceTest {
|
||||
public void testRecording_noTracks() throws Exception {
|
||||
// given
|
||||
List<Track> tracks = contentProviderUtils.getTracks();
|
||||
Assert.assertTrue(tracks.isEmpty());
|
||||
assertTrue(tracks.isEmpty());
|
||||
|
||||
// when
|
||||
Intent startIntent = createStartIntent(context);
|
||||
@@ -144,8 +150,8 @@ public class TrackRecordingServiceTest {
|
||||
|
||||
// then
|
||||
// Test if we start in no-recording mode by default.
|
||||
Assert.assertFalse(service.isRecording());
|
||||
Assert.assertNull(service.getRecordingTrackId());
|
||||
assertFalse(service.isRecording());
|
||||
assertNull(service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -158,8 +164,8 @@ public class TrackRecordingServiceTest {
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
|
||||
// then
|
||||
Assert.assertFalse(service.isRecording());
|
||||
Assert.assertNull(service.getRecordingTrackId());
|
||||
assertFalse(service.isRecording());
|
||||
assertNull(service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -172,7 +178,7 @@ public class TrackRecordingServiceTest {
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
|
||||
// then
|
||||
Assert.assertTrue(service.isRecording());
|
||||
assertTrue(service.isRecording());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -187,21 +193,21 @@ public class TrackRecordingServiceTest {
|
||||
service.pauseCurrentTrack();
|
||||
|
||||
// then
|
||||
Assert.assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
|
||||
assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
|
||||
|
||||
//when
|
||||
service.resumeTrack(trackId);
|
||||
newTrackPoint(service);
|
||||
|
||||
// then
|
||||
Assert.assertTrue(service.isRecording());
|
||||
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
||||
assertTrue(service.isRecording());
|
||||
assertEquals(trackId, service.getRecordingTrackId());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertEquals(5, trackPoints.size());
|
||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
||||
Assert.assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(3).getLatitude(), 0.01);
|
||||
assertEquals(5, trackPoints.size());
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
||||
assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(3).getLatitude(), 0.01);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -213,23 +219,23 @@ public class TrackRecordingServiceTest {
|
||||
newTrackPoint(service);
|
||||
service.endCurrentTrack();
|
||||
|
||||
Assert.assertEquals(1, contentProviderUtils.getTrackPoints(trackId).size());
|
||||
assertEquals(1, contentProviderUtils.getTrackPoints(trackId).size());
|
||||
|
||||
// when
|
||||
service.resumeTrack(trackId);
|
||||
newTrackPoint(service);
|
||||
|
||||
// then
|
||||
Assert.assertTrue(service.isRecording());
|
||||
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
||||
assertTrue(service.isRecording());
|
||||
assertEquals(trackId, service.getRecordingTrackId());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertEquals(4, trackPoints.size());
|
||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
Assert.assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
||||
assertEquals(4, trackPoints.size());
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
||||
}
|
||||
|
||||
@FlakyTest(detail = "Sometimes fails on CI.")
|
||||
@Ignore("Sometimes fails on CI.")
|
||||
@MediumTest
|
||||
@Test
|
||||
public void testRecording_orphanedRecordingTrack() throws Exception {
|
||||
@@ -242,8 +248,8 @@ public class TrackRecordingServiceTest {
|
||||
PreferencesUtils.setLong(context, R.string.recording_track_id_key, 123L);
|
||||
|
||||
// then
|
||||
Assert.assertFalse(service.isRecording());
|
||||
Assert.assertNull(service.getRecordingTrackId());
|
||||
assertFalse(service.isRecording());
|
||||
assertNull(service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -252,7 +258,7 @@ public class TrackRecordingServiceTest {
|
||||
// given
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
service.startNewTrack();
|
||||
Assert.assertTrue(service.isRecording());
|
||||
assertTrue(service.isRecording());
|
||||
|
||||
Track.Id trackId = service.getRecordingTrackId();
|
||||
|
||||
@@ -260,10 +266,10 @@ public class TrackRecordingServiceTest {
|
||||
Track.Id newTrackId = service.startNewTrack();
|
||||
|
||||
// then
|
||||
Assert.assertNull(newTrackId);
|
||||
assertNull(newTrackId);
|
||||
|
||||
Assert.assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
||||
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
||||
assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
||||
assertEquals(trackId, service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -271,15 +277,15 @@ public class TrackRecordingServiceTest {
|
||||
public void testEndCurrentTrack_noRecording() throws Exception {
|
||||
// given
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
// when
|
||||
// Ending the current track when there is no recording should not result in any error.
|
||||
service.endCurrentTrack();
|
||||
|
||||
// then
|
||||
Assert.assertFalse(PreferencesUtils.isRecording(context));
|
||||
Assert.assertNull(service.getRecordingTrackId());
|
||||
assertFalse(PreferencesUtils.isRecording(context));
|
||||
assertNull(service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -287,13 +293,13 @@ public class TrackRecordingServiceTest {
|
||||
public void testInsertWaypointMarker_noRecordingTrack() throws Exception {
|
||||
// given
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
// when
|
||||
Waypoint.Id waypointId = service.insertWaypoint(null, null, null, null);
|
||||
Marker.Id waypointId = service.insertMarker(null, null, null, null);
|
||||
|
||||
// then
|
||||
Assert.assertNull(waypointId);
|
||||
assertNull(waypointId);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -302,29 +308,29 @@ public class TrackRecordingServiceTest {
|
||||
// given
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
service.startNewTrack();
|
||||
Assert.assertTrue(service.isRecording());
|
||||
assertTrue(service.isRecording());
|
||||
newTrackPoint(service);
|
||||
Track.Id trackId = service.getRecordingTrackId();
|
||||
|
||||
// when
|
||||
Waypoint.Id waypointId = service.insertWaypoint(null, null, null, null);
|
||||
Marker.Id waypointId = service.insertMarker(null, null, null, null);
|
||||
|
||||
// then
|
||||
Assert.assertNotEquals(-1L, waypointId);
|
||||
Waypoint wpt = contentProviderUtils.getWaypoint(waypointId);
|
||||
Assert.assertEquals(context.getString(R.string.marker_waypoint_icon_url), wpt.getIcon());
|
||||
Assert.assertEquals(context.getString(R.string.marker_name_format, 1), wpt.getName());
|
||||
Assert.assertEquals(trackId, wpt.getTrackId());
|
||||
Assert.assertEquals(0.0, wpt.getLength(), 0.01);
|
||||
Assert.assertNotNull(wpt.getLocation());
|
||||
assertNotEquals(-1L, waypointId);
|
||||
Marker wpt = contentProviderUtils.getMarker(waypointId);
|
||||
assertEquals(context.getString(R.string.marker_icon_url), wpt.getIcon());
|
||||
assertEquals(context.getString(R.string.marker_name_format, 1), wpt.getName());
|
||||
assertEquals(trackId, wpt.getTrackId());
|
||||
assertEquals(0.0, wpt.getLength(), 0.01);
|
||||
assertNotNull(wpt.getLocation());
|
||||
|
||||
service.endCurrentTrack();
|
||||
}
|
||||
|
||||
private void addTrack(Track track, boolean isRecording) {
|
||||
Assert.assertTrue(track.getId().isValid());
|
||||
assertTrue(track.getId().isValid());
|
||||
contentProviderUtils.insertTrack(track);
|
||||
Assert.assertEquals(track.getId(), contentProviderUtils.getTrack(track.getId()).getId());
|
||||
assertEquals(track.getId(), contentProviderUtils.getTrack(track.getId()).getId());
|
||||
PreferencesUtils.setLong(context, R.string.recording_track_id_key, isRecording ? track.getId().getId() : PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
||||
PreferencesUtils.setBoolean(context, R.string.recording_track_paused_key, !isRecording);
|
||||
}
|
||||
|
||||
+37
-35
@@ -12,7 +12,6 @@ import androidx.test.rule.GrantPermissionRule;
|
||||
import androidx.test.rule.ServiceTestRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
@@ -33,6 +32,9 @@ import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* Tests insert location.
|
||||
* <p>
|
||||
@@ -103,11 +105,11 @@ public class TrackRecordingServiceTestLocation {
|
||||
service.endCurrentTrack();
|
||||
|
||||
// then
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertEquals(6, trackPoints.size());
|
||||
Assert.assertEquals(45.0005, trackPoints.get(5).getLatitude(), 0.01);
|
||||
assertEquals(6, trackPoints.size());
|
||||
assertEquals(45.0005, trackPoints.get(5).getLatitude(), 0.01);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -127,11 +129,11 @@ public class TrackRecordingServiceTestLocation {
|
||||
service.endCurrentTrack();
|
||||
|
||||
// then
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertEquals(2, trackPoints.size());
|
||||
Assert.assertEquals(45.000005, trackPoints.get(1).getLatitude(), 0.01);
|
||||
assertEquals(2, trackPoints.size());
|
||||
assertEquals(45.000005, trackPoints.get(1).getLatitude(), 0.01);
|
||||
}
|
||||
|
||||
// @MediumTest
|
||||
@@ -169,13 +171,13 @@ public class TrackRecordingServiceTestLocation {
|
||||
service.endCurrentTrack();
|
||||
|
||||
// then
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertEquals(3, trackPoints.size());
|
||||
Assert.assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(6, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(3, trackPoints.size());
|
||||
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(6, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -195,14 +197,14 @@ public class TrackRecordingServiceTestLocation {
|
||||
service.endCurrentTrack();
|
||||
|
||||
// then
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertEquals(4, trackPoints.size());
|
||||
Assert.assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(5, trackPoints.get(2).getAccuracy(), 0.01); //TODO Check why this trackPoint is inserted.
|
||||
Assert.assertEquals(6, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(4, trackPoints.size());
|
||||
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(2).getAccuracy(), 0.01); //TODO Check why this trackPoint is inserted.
|
||||
assertEquals(6, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
}
|
||||
|
||||
|
||||
@@ -238,16 +240,16 @@ public class TrackRecordingServiceTestLocation {
|
||||
service.endCurrentTrack();
|
||||
|
||||
// then
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertEquals(6, trackPoints.size());
|
||||
Assert.assertEquals(0, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(1, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(4, trackPoints.get(4).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(5, trackPoints.get(5).getAccuracy(), 0.01);
|
||||
assertEquals(6, trackPoints.size());
|
||||
assertEquals(0, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
assertEquals(1, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(4, trackPoints.get(4).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(5).getAccuracy(), 0.01);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -266,16 +268,16 @@ public class TrackRecordingServiceTestLocation {
|
||||
service.endCurrentTrack();
|
||||
|
||||
// then
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
Assert.assertEquals(7, trackPoints.size());
|
||||
Assert.assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
Assert.assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(4).getLatitude(), 0.01);
|
||||
Assert.assertEquals(4, trackPoints.get(5).getAccuracy(), 0.01);
|
||||
Assert.assertEquals(5, trackPoints.get(6).getAccuracy(), 0.01);
|
||||
assertEquals(7, trackPoints.size());
|
||||
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(4).getLatitude(), 0.01);
|
||||
assertEquals(4, trackPoints.get(5).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(6).getAccuracy(), 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
+22
-17
@@ -13,7 +13,6 @@ import androidx.test.rule.ServiceTestRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
@@ -32,6 +31,12 @@ import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for the track recording service, which require a {@link Looper}.
|
||||
*
|
||||
@@ -188,23 +193,23 @@ public class TrackRecordingServiceTestLooper {
|
||||
@Test
|
||||
public void testIntegration_completeRecordingSession() throws TimeoutException {
|
||||
List<Track> tracks = contentProviderUtils.getTracks();
|
||||
Assert.assertTrue(tracks.isEmpty());
|
||||
assertTrue(tracks.isEmpty());
|
||||
fullRecordingSession();
|
||||
}
|
||||
|
||||
private void fullRecordingSession() throws TimeoutException {
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)));
|
||||
Assert.assertFalse(service.isRecording());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
// Start a track.
|
||||
Track.Id trackId = service.startNewTrack();
|
||||
Assert.assertTrue(trackId.isValid());
|
||||
Assert.assertTrue(service.isRecording());
|
||||
assertTrue(trackId.isValid());
|
||||
assertTrue(service.isRecording());
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
Assert.assertNotNull(track);
|
||||
Assert.assertEquals(trackId, track.getId());
|
||||
Assert.assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
||||
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
||||
assertNotNull(track);
|
||||
assertEquals(trackId, track.getId());
|
||||
assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
||||
assertEquals(trackId, service.getRecordingTrackId());
|
||||
|
||||
// Insert a few points, markers and statistics.
|
||||
long startTime = System.currentTimeMillis();
|
||||
@@ -221,20 +226,20 @@ public class TrackRecordingServiceTestLooper {
|
||||
service.newTrackPoint(trackPoint, prefAccuracy);
|
||||
|
||||
if (i % 7 == 0) {
|
||||
service.insertWaypoint(null, null, null, null);
|
||||
service.insertMarker(null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the track. Validate if it has correct data.
|
||||
service.endCurrentTrack();
|
||||
Assert.assertFalse(service.isRecording());
|
||||
Assert.assertNull(service.getRecordingTrackId());
|
||||
assertFalse(service.isRecording());
|
||||
assertNull(service.getRecordingTrackId());
|
||||
track = contentProviderUtils.getTrack(trackId);
|
||||
Assert.assertNotNull(track);
|
||||
Assert.assertEquals(trackId, track.getId());
|
||||
assertNotNull(track);
|
||||
assertEquals(trackId, track.getId());
|
||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||
Assert.assertNotNull(trackStatistics);
|
||||
Assert.assertTrue(trackStatistics.getStartTime_ms() > 0);
|
||||
Assert.assertTrue(trackStatistics.getStopTime_ms() >= trackStatistics.getStartTime_ms());
|
||||
assertNotNull(trackStatistics);
|
||||
assertTrue(trackStatistics.getStartTime_ms() > 0);
|
||||
assertTrue(trackStatistics.getStopTime_ms() >= trackStatistics.getStartTime_ms());
|
||||
}
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package de.dennisguse.opentracks.services.sensors;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* NOTE: Test data is completely artificial.
|
||||
*/
|
||||
public class ElevationSumManagerTest {
|
||||
|
||||
private ElevationSumManager elevationSumManager = new ElevationSumManager();
|
||||
|
||||
private static void addSensorValue(ElevationSumManager elevationSumManager, float[] values) {
|
||||
for (float f : values) {
|
||||
elevationSumManager.onSensorValueChanged(f);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
elevationSumManager.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getElevationGainLoss_downhill() {
|
||||
// given
|
||||
elevationSumManager.setConnected(true);
|
||||
|
||||
// then
|
||||
addSensorValue(elevationSumManager, new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1015.14f, 1015.15f});
|
||||
|
||||
// then
|
||||
Assert.assertEquals(0f, elevationSumManager.getElevationGain_m(), 0.01);
|
||||
Assert.assertEquals(-48.0, elevationSumManager.getElevationLoss_m(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensorUnavailable() {
|
||||
// given
|
||||
elevationSumManager.setConnected(false);
|
||||
|
||||
// then
|
||||
elevationSumManager.onSensorValueChanged(999f);
|
||||
|
||||
// then
|
||||
Assert.assertNull(elevationSumManager.getElevationGain_m());
|
||||
Assert.assertNull(elevationSumManager.getElevationLoss_m());
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -23,11 +23,12 @@ import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link AnnouncementPeriodicTaskFactory}.
|
||||
*
|
||||
@@ -53,6 +54,6 @@ public class AnnouncementPeriodicTaskFactoryTest {
|
||||
public void testCreate() {
|
||||
PeriodicTaskFactory factory = new AnnouncementPeriodicTaskFactory();
|
||||
PeriodicTask task = factory.create(context);
|
||||
Assert.assertTrue(task instanceof AnnouncementPeriodicTask);
|
||||
assertTrue(task instanceof AnnouncementPeriodicTask);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
*/
|
||||
package de.dennisguse.opentracks.stats;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link TrackStatistics}.
|
||||
* This only tests non-trivial pieces of that class.
|
||||
@@ -50,8 +51,8 @@ public class TrackStatisticsTest {
|
||||
statistics2.setMovingTime(600L); // Result: 700+600
|
||||
statistics.setTotalDistance(750.0);
|
||||
statistics2.setTotalDistance(350.0); // Result: 750+350
|
||||
statistics.setTotalElevationGain(50.0);
|
||||
statistics2.setTotalElevationGain(850.0); // Result: 850+50
|
||||
statistics.setTotalElevationGain(50.0f);
|
||||
statistics2.setTotalElevationGain(850.0f); // Result: 850+50
|
||||
statistics.setMaxSpeed(60.0); // Resulting max speed
|
||||
statistics2.setMaxSpeed(30.0);
|
||||
statistics.setMaxElevation(1250.0);
|
||||
@@ -61,28 +62,28 @@ public class TrackStatisticsTest {
|
||||
|
||||
statistics.merge(statistics2);
|
||||
|
||||
Assert.assertEquals(1000L, statistics.getStartTime_ms());
|
||||
Assert.assertEquals(4000L, statistics.getStopTime_ms());
|
||||
Assert.assertEquals(2500L, statistics.getTotalTime());
|
||||
Assert.assertEquals(1300L, statistics.getMovingTime());
|
||||
Assert.assertEquals(1100.0, statistics.getTotalDistance(), 0.001);
|
||||
Assert.assertEquals(900.0, statistics.getTotalElevationGain(), 0.001);
|
||||
Assert.assertEquals(statistics.getTotalDistance() / (statistics.getMovingTime() / 1000.0), statistics.getMaxSpeed(), 0.001);
|
||||
Assert.assertEquals(1200.0, statistics.getMinElevation(), 0.001);
|
||||
Assert.assertEquals(3575.0, statistics.getMaxElevation(), 0.001);
|
||||
assertEquals(1000L, statistics.getStartTime_ms());
|
||||
assertEquals(4000L, statistics.getStopTime_ms());
|
||||
assertEquals(2500L, statistics.getTotalTime());
|
||||
assertEquals(1300L, statistics.getMovingTime());
|
||||
assertEquals(1100.0, statistics.getTotalDistance(), 0.001);
|
||||
assertEquals(900.0, statistics.getTotalElevationGain(), 0.001);
|
||||
assertEquals(statistics.getTotalDistance() / (statistics.getMovingTime() / 1000.0), statistics.getMaxSpeed(), 0.001);
|
||||
assertEquals(1200.0, statistics.getMinElevation(), 0.001);
|
||||
assertEquals(3575.0, statistics.getMaxElevation(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAverageSpeed() {
|
||||
statistics.setTotalDistance(1000.0);
|
||||
statistics.setTotalTime(50000); // in milliseconds
|
||||
Assert.assertEquals(20.0, statistics.getAverageSpeed(), 0.001);
|
||||
assertEquals(20.0, statistics.getAverageSpeed(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAverageMovingSpeed() {
|
||||
statistics.setTotalDistance(1000.0);
|
||||
statistics.setMovingTime(20000); // in milliseconds
|
||||
Assert.assertEquals(50.0, statistics.getAverageMovingSpeed(), 0.001);
|
||||
assertEquals(50.0, statistics.getAverageMovingSpeed(), 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,20 @@ import android.content.Context;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AnnouncementUtilsTest {
|
||||
@@ -26,9 +35,50 @@ public class AnnouncementUtilsTest {
|
||||
stats.setTotalElevationGain(6000);
|
||||
|
||||
// when
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane");
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane", null);
|
||||
|
||||
// then
|
||||
Assert.assertEquals("OpenTracks total distance 20.00 kilometers in 5 minutes 0 seconds at 240.0 kilometers per hour", announcement);
|
||||
assertEquals("OpenTracks total distance 20.00 kilometers in 5 minutes 0 seconds at 240.0 kilometers per hour", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_withInterval() {
|
||||
TrackStatistics stats = new TrackStatistics();
|
||||
stats.setTotalDistance(20000);
|
||||
stats.setTotalTime(600000);
|
||||
stats.setMovingTime(300000);
|
||||
stats.setMaxSpeed(100);
|
||||
stats.setTotalElevationGain(6000);
|
||||
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||
List<TrackPoint> trackPoints = Arrays.asList(TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second);
|
||||
intervalStatistics.build(trackPoints, 1000);
|
||||
IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
||||
|
||||
int speedId = R.plurals.voiceSpeedKilometersPerHour;
|
||||
double kmPerHour = lastInterval.getSpeed_ms() * UnitConversions.MPS_TO_KMH;
|
||||
|
||||
String firstPartMsg = "OpenTracks total distance 20.00 kilometers in 5 minutes 0 seconds at 240.0 kilometers per hour";
|
||||
String rateMsg = " Lap speed of " + context.getResources().getQuantityString(speedId, getQuantityCount(kmPerHour), kmPerHour);
|
||||
String msg = firstPartMsg + rateMsg;
|
||||
|
||||
// when
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane", lastInterval);
|
||||
|
||||
// then
|
||||
assertEquals(msg, announcement);
|
||||
}
|
||||
|
||||
private int getQuantityCount(double d) {
|
||||
if (d == 0) {
|
||||
return 0;
|
||||
} else if (d == 1) {
|
||||
return 1;
|
||||
} else if (d == 2) {
|
||||
return 2;
|
||||
} else {
|
||||
int count = (int) d;
|
||||
return Math.max(count, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,13 @@ package de.dennisguse.opentracks.util;
|
||||
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public class BluetoothUtilsTest {
|
||||
|
||||
@Test
|
||||
@@ -19,7 +21,7 @@ public class BluetoothUtilsTest {
|
||||
int heartRate = BluetoothUtils.parseHeartRate(characteristic);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(60, heartRate);
|
||||
assertEquals(60, heartRate);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -32,7 +34,7 @@ public class BluetoothUtilsTest {
|
||||
int heartRate = BluetoothUtils.parseHeartRate(characteristic);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(257, heartRate);
|
||||
assertEquals(257, heartRate);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -44,8 +46,8 @@ public class BluetoothUtilsTest {
|
||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||
Assert.assertNull(sensor.getSpeed());
|
||||
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||
assertNull(sensor.getSpeed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -57,8 +59,8 @@ public class BluetoothUtilsTest {
|
||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||
|
||||
// then
|
||||
Assert.assertNull(sensor.getCadence());
|
||||
Assert.assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
||||
assertNull(sensor.getCadence());
|
||||
assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -70,7 +72,7 @@ public class BluetoothUtilsTest {
|
||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||
Assert.assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
||||
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||
assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package de.dennisguse.opentracks.util;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
@@ -23,6 +22,8 @@ import org.junit.runners.JUnit4;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link FileUtils}.
|
||||
*
|
||||
@@ -37,7 +38,7 @@ public class FileUtilsTest {
|
||||
@Test
|
||||
public void testBuildUniqueFileName_new() {
|
||||
String filename = FileUtils.buildUniqueFileName(new File("/dir"), "Filename", "ext");
|
||||
Assert.assertEquals("Filename.ext", filename);
|
||||
assertEquals("Filename.ext", filename);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +48,7 @@ public class FileUtilsTest {
|
||||
public void testBuildUniqueFileName_exist() {
|
||||
// Expect "/default.prop" to exist on the phone/emulator
|
||||
String filename = FileUtils.buildUniqueFileName(new File("/"), "default", "prop");
|
||||
Assert.assertEquals("default(1).prop", filename);
|
||||
assertEquals("default(1).prop", filename);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,13 +59,13 @@ public class FileUtilsTest {
|
||||
public void testSanitizeFileName() {
|
||||
String name = "Swim\10ming-^across:/the/ pacific (ocean).";
|
||||
String expected = "Swim_ming-^across_the_ pacific (ocean).";
|
||||
Assert.assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSanitizeFileNameWithSuffix() {
|
||||
String name = "FileName.jpeg";
|
||||
Assert.assertEquals(name, FileUtils.sanitizeFileName(name));
|
||||
assertEquals(name, FileUtils.sanitizeFileName(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +76,7 @@ public class FileUtilsTest {
|
||||
public void testSanitizeFileName_i18n() {
|
||||
String name = "您好-привет";
|
||||
String expected = "您好-привет";
|
||||
Assert.assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +87,7 @@ public class FileUtilsTest {
|
||||
public void testSanitizeFileName_special_characters() {
|
||||
String name = "$%'-_@~`!(){}^#&+,;=[] ";
|
||||
String expected = "$%'-_@~`!(){}^#&+,;=[] ";
|
||||
Assert.assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +98,7 @@ public class FileUtilsTest {
|
||||
public void testSanitizeFileName_collapse() {
|
||||
String name = "hello//there";
|
||||
String expected = "hello_there";
|
||||
Assert.assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,8 +115,8 @@ public class FileUtilsTest {
|
||||
String truncated = FileUtils.truncateFileName(directory, nameString, suffix);
|
||||
|
||||
for (int i = 0; i < truncated.length(); i++) {
|
||||
Assert.assertEquals('a', truncated.charAt(i));
|
||||
assertEquals('a', truncated.charAt(i));
|
||||
}
|
||||
Assert.assertEquals(FileUtils.MAX_FAT32_PATH_LENGTH, new File(directory, truncated + suffix).getPath().length());
|
||||
assertEquals(FileUtils.MAX_FAT32_PATH_LENGTH, new File(directory, truncated + suffix).getPath().length());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@ import android.content.SharedPreferences;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PreferencesUtilsTest {
|
||||
|
||||
@@ -29,7 +30,7 @@ public class PreferencesUtilsTest {
|
||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL, trackFileFormat);
|
||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL, trackFileFormat);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -43,7 +44,7 @@ public class PreferencesUtilsTest {
|
||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -57,6 +58,6 @@ public class PreferencesUtilsTest {
|
||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package de.dennisguse.opentracks.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public class PressureSensorUtilsTest {
|
||||
|
||||
// real data at 500Hz stationary
|
||||
@Test
|
||||
public void elevationChanges_none() {
|
||||
// given
|
||||
float[] sensorValues_hPa = new float[]{1015.6876f, 1015.699f, 1015.70905f, 1015.71075f, 1015.7224f, 1015.72f, 1015.7373f, 1015.7481f, 1015.74133f, 1015.73553f, 1015.7462f, 1015.74896f, 1015.752f, 1015.754f, 1015.7456f, 1015.73303f, 1015.7288f, 1015.7239f, 1015.7298f, 1015.7387f, 1015.72534f, 1015.72577f, 1015.72797f, 1015.71796f, 1015.7113f, 1015.7097f, 1015.7096f, 1015.7013f, 1015.7072f, 1015.71063f, 1015.7088f, 1015.7115f, 1015.713f, 1015.7121f, 1015.7062f, 1015.7062f, 1015.6994f, 1015.69617f, 1015.68945f, 1015.698f, 1015.6913f, 1015.69696f, 1015.69293f, 1015.6955f, 1015.6928f, 1015.6939f, 1015.68787f, 1015.6881f, 1015.68536f, 1015.68726f, 1015.6879f, 1015.6904f, 1015.6937f, 1015.69476f, 1015.7046f, 1015.7019f, 1015.7079f, 1015.71124f, 1015.71216f, 1015.71436f, 1015.7171f, 1015.7186f, 1015.7186f, 1015.7246f, 1015.72046f, 1015.7211f, 1015.72375f, 1015.7194f, 1015.72125f, 1015.7161f, 1015.71185f, 1015.7188f, 1015.721f, 1015.7252f, 1015.72266f, 1015.7236f, 1015.72614f, 1015.7266f, 1015.7344f, 1015.7376f, 1015.7337f, 1015.7253f, 1015.71875f, 1015.7219f, 1015.7219f, 1015.7317f, 1015.7284f, 1015.73444f, 1015.73584f, 1015.7369f, 1015.73254f, 1015.7369f, 1015.7336f, 1015.73254f, 1015.73676f, 1015.74176f, 1015.74506f, 1015.7478f, 1015.755f, 1015.7515f, 1015.7543f, 1015.7459f, 1015.7468f, 1015.7492f, 1015.74585f, 1015.74756f, 1015.74756f, 1015.75085f, 1015.754f, 1015.75336f, 1015.7568f, 1015.75165f, 1015.761f, 1015.7527f, 1015.75684f, 1015.7635f, 1015.7585f, 1015.7552f, 1015.7475f, 1015.74506f, 1015.7542f, 1015.75586f, 1015.74176f, 1015.74414f, 1015.7501f, 1015.751f, 1015.7478f, 1015.755f, 1015.75836f, 1015.7592f, 1015.75256f, 1015.7559f, 1015.76654f, 1015.76154f, 1015.766f, 1015.77014f, 1015.76904f, 1015.76013f, 1015.7674f, 1015.76514f, 1015.7674f, 1015.7635f, 1015.76404f, 1015.7607f, 1015.754f, 1015.7574f, 1015.7607f, 1015.7607f, 1015.7607f, 1015.754f, 1015.7567f, 1015.7616f, 1015.7643f, 1015.7666f, 1015.7609f, 1015.766f, 1015.76764f, 1015.755f, 1015.75757f, 1015.74927f, 1015.74927f, 1015.7426f, 1015.745f, 1015.745f, 1015.7409f, 1015.7376f, 1015.7326f, 1015.74164f, 1015.74664f, 1015.745f, 1015.7459f, 1015.7502f, 1015.7493f, 1015.7476f, 1015.7493f, 1015.751f, 1015.7601f, 1015.76434f, 1015.766f, 1015.756f, 1015.7617f, 1015.7623f, 1015.76404f, 1015.76733f, 1015.7607f, 1015.7623f, 1015.76337f, 1015.7584f, 1015.7573f, 1015.7502f, 1015.7534f, 1015.7534f, 1015.7601f, 1015.75684f, 1015.7518f, 1015.75574f, 1015.7524f, 1015.7507f, 1015.7484f, 1015.7502f, 1015.7534f, 1015.7623f, 1015.75903f, 1015.75574f, 1015.75574f, 1015.7573f, 1015.7524f, 1015.75574f, 1015.75574f, 1015.7607f, 1015.7573f, 1015.754f, 1015.74677f, 1015.754f, 1015.75574f, 1015.75903f, 1015.7573f, 1015.7551f, 1015.7573f, 1015.754f, 1015.7507f, 1015.7374f, 1015.739f, 1015.73566f, 1015.73566f, 1015.7367f, 1015.7417f, 1015.7417f, 1015.739f, 1015.74835f, 1015.74567f, 1015.7517f, 1015.74066f, 1015.7374f, 1015.739f, 1015.7417f, 1015.73065f, 1015.72894f, 1015.73505f, 1015.73334f, 1015.74005f, 1015.74005f, 1015.7367f, 1015.7434f, 1015.744f, 1015.7423f, 1015.7384f, 1015.739f, 1015.7374f, 1015.7374f, 1015.7374f, 1015.7341f, 1015.73505f, 1015.7341f, 1015.7267f, 1015.72833f, 1015.7234f, 1015.7167f, 1015.725f, 1015.7217f, 1015.7234f, 1015.73004f, 1015.7324f, 1015.7423f, 1015.74005f, 1015.73505f, 1015.73004f, 1015.739f, 1015.7417f, 1015.74567f, 1015.74066f, 1015.74146f, 1015.74146f, 1015.73816f, 1015.7274f, 1015.72906f, 1015.7274f, 1015.7341f, 1015.739f, 1015.744f, 1015.7417f, 1015.7374f, 1015.7324f, 1015.73816f, 1015.74146f, 1015.7374f, 1015.7341f, 1015.7365f, 1015.7365f, 1015.74146f, 1015.74414f, 1015.7475f, 1015.7448f, 1015.74146f, 1015.74585f, 1015.7475f, 1015.75146f, 1015.75146f, 1015.7591f, 1015.75476f, 1015.7614f, 1015.75476f, 1015.7492f, 1015.74817f, 1015.7498f, 1015.7515f, 1015.75586f, 1015.7509f, 1015.7448f, 1015.7525f, 1015.7581f, 1015.7592f};
|
||||
float firstSensorValue = sensorValues_hPa[0];
|
||||
|
||||
// when // then
|
||||
for (float v : sensorValues_hPa) {
|
||||
assertNull(PressureSensorUtils.computeChanges_m(firstSensorValue, v));
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate a sudden drop of elevation.
|
||||
// test data
|
||||
@Test
|
||||
public void computeChanges_downhill() {
|
||||
float[] sensorValues_hPa = new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1018f, 1018.1f, 1018.1f, 1018.1f, 1018.1f};
|
||||
float firstSensorValue = sensorValues_hPa[0];
|
||||
|
||||
// when
|
||||
float elevationGain_m = 0;
|
||||
float elevationLoss_m = 0;
|
||||
float lastUsedPressureValue_hPa = firstSensorValue;
|
||||
|
||||
for (float v : sensorValues_hPa) {
|
||||
PressureSensorUtils.ElevationChange elevationChange = PressureSensorUtils.computeChanges_m(lastUsedPressureValue_hPa, v);
|
||||
if (elevationChange != null) {
|
||||
elevationGain_m += elevationChange.getElevationGain_m();
|
||||
elevationLoss_m += elevationChange.getElevationLoss_m();
|
||||
lastUsedPressureValue_hPa = elevationChange.getCurrentSensorValue_hPa();
|
||||
}
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals(0f, elevationGain_m, 0.01);
|
||||
assertEquals(-15.0f, elevationLoss_m, 0.01);
|
||||
assertEquals(1016.80f, lastUsedPressureValue_hPa, 0.01); //Expect exponential smoothing
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,15 @@ import android.content.Context;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link StringUtils}.
|
||||
*
|
||||
@@ -44,7 +46,7 @@ public class StringUtilsTest {
|
||||
*/
|
||||
@Test
|
||||
public void testFormatDateTimeIso8601() {
|
||||
Assert.assertEquals("1970-01-01T00:00:12.345Z", StringUtils.formatDateTimeIso8601(12345));
|
||||
assertEquals("1970-01-01T00:00:12.345Z", StringUtils.formatDateTimeIso8601(12345));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,19 +55,19 @@ public class StringUtilsTest {
|
||||
@Test
|
||||
public void testformatElapsedTime() {
|
||||
// 1 second
|
||||
Assert.assertEquals("00:01", StringUtils.formatElapsedTime(1000));
|
||||
assertEquals("00:01", StringUtils.formatElapsedTime(1000));
|
||||
// 10 seconds
|
||||
Assert.assertEquals("00:10", StringUtils.formatElapsedTime(10000));
|
||||
assertEquals("00:10", StringUtils.formatElapsedTime(10000));
|
||||
// 1 minute
|
||||
Assert.assertEquals("01:00", StringUtils.formatElapsedTime(60000));
|
||||
assertEquals("01:00", StringUtils.formatElapsedTime(60000));
|
||||
// 10 minutes
|
||||
Assert.assertEquals("10:00", StringUtils.formatElapsedTime(600000));
|
||||
assertEquals("10:00", StringUtils.formatElapsedTime(600000));
|
||||
// 1 hour
|
||||
Assert.assertEquals("1:00:00", StringUtils.formatElapsedTime(3600000));
|
||||
assertEquals("1:00:00", StringUtils.formatElapsedTime(3600000));
|
||||
// 10 hours
|
||||
Assert.assertEquals("10:00:00", StringUtils.formatElapsedTime(36000000));
|
||||
assertEquals("10:00:00", StringUtils.formatElapsedTime(36000000));
|
||||
// 100 hours
|
||||
Assert.assertEquals("100:00:00", StringUtils.formatElapsedTime(360000000));
|
||||
assertEquals("100:00:00", StringUtils.formatElapsedTime(360000000));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,19 +76,19 @@ public class StringUtilsTest {
|
||||
@Test
|
||||
public void testformatElapsedTimeWithHour() {
|
||||
// 1 second
|
||||
Assert.assertEquals("0:00:01", StringUtils.formatElapsedTimeWithHour(1000));
|
||||
assertEquals("0:00:01", StringUtils.formatElapsedTimeWithHour(1000));
|
||||
// 10 seconds
|
||||
Assert.assertEquals("0:00:10", StringUtils.formatElapsedTimeWithHour(10000));
|
||||
assertEquals("0:00:10", StringUtils.formatElapsedTimeWithHour(10000));
|
||||
// 1 minute
|
||||
Assert.assertEquals("0:01:00", StringUtils.formatElapsedTimeWithHour(60000));
|
||||
assertEquals("0:01:00", StringUtils.formatElapsedTimeWithHour(60000));
|
||||
// 10 minutes
|
||||
Assert.assertEquals("0:10:00", StringUtils.formatElapsedTimeWithHour(600000));
|
||||
assertEquals("0:10:00", StringUtils.formatElapsedTimeWithHour(600000));
|
||||
// 1 hour
|
||||
Assert.assertEquals("1:00:00", StringUtils.formatElapsedTimeWithHour(3600000));
|
||||
assertEquals("1:00:00", StringUtils.formatElapsedTimeWithHour(3600000));
|
||||
// 10 hours
|
||||
Assert.assertEquals("10:00:00", StringUtils.formatElapsedTimeWithHour(36000000));
|
||||
assertEquals("10:00:00", StringUtils.formatElapsedTimeWithHour(36000000));
|
||||
// 100 hours
|
||||
Assert.assertEquals("100:00:00", StringUtils.formatElapsedTimeWithHour(360000000));
|
||||
assertEquals("100:00:00", StringUtils.formatElapsedTimeWithHour(360000000));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,13 +98,13 @@ public class StringUtilsTest {
|
||||
@Test
|
||||
public void testFormatDistance() {
|
||||
// A large number in metric
|
||||
Assert.assertEquals("5.00 km", StringUtils.formatDistance(context, 5000, true));
|
||||
assertEquals("5.00 km", StringUtils.formatDistance(context, 5000, true));
|
||||
// A large number in imperial
|
||||
Assert.assertEquals("3.11 mi", StringUtils.formatDistance(context, 5000, false));
|
||||
assertEquals("3.11 mi", StringUtils.formatDistance(context, 5000, false));
|
||||
// A small number in metric
|
||||
Assert.assertEquals("100.00 m", StringUtils.formatDistance(context, 100, true));
|
||||
assertEquals("100.00 m", StringUtils.formatDistance(context, 100, true));
|
||||
// A small number in imperial
|
||||
Assert.assertEquals("328.08 ft", StringUtils.formatDistance(context, 100, false));
|
||||
assertEquals("328.08 ft", StringUtils.formatDistance(context, 100, false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,8 +112,8 @@ public class StringUtilsTest {
|
||||
*/
|
||||
@Test
|
||||
public void testFormatCData() {
|
||||
Assert.assertEquals("<![CDATA[hello]]>", StringUtils.formatCData("hello"));
|
||||
Assert.assertEquals("<![CDATA[hello]]]]><![CDATA[>there]]>", StringUtils.formatCData("hello]]>there"));
|
||||
assertEquals("<![CDATA[hello]]>", StringUtils.formatCData("hello"));
|
||||
assertEquals("<![CDATA[hello]]]]><![CDATA[>there]]>", StringUtils.formatCData("hello]]>there"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,7 +170,7 @@ public class StringUtilsTest {
|
||||
|
||||
// This comparision tends to be flaky (difference of 1ms)
|
||||
// Assert.assertEquals(calendar.getTimeInMillis(), StringUtils.parseTime(xmlDateTime));
|
||||
Assert.assertTrue(calendar.getTimeInMillis() + " vs. " + StringUtils.parseTime(xmlDateTime), Math.abs(calendar.getTimeInMillis() - StringUtils.parseTime(xmlDateTime)) <= 1);
|
||||
assertTrue(calendar.getTimeInMillis() + " vs. " + StringUtils.parseTime(xmlDateTime), Math.abs(calendar.getTimeInMillis() - StringUtils.parseTime(xmlDateTime)) <= 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,9 +179,9 @@ public class StringUtilsTest {
|
||||
@Test
|
||||
public void testGetTimeParts_positive() {
|
||||
int[] parts = StringUtils.getTimeParts(61000);
|
||||
Assert.assertEquals(1, parts[0]);
|
||||
Assert.assertEquals(1, parts[1]);
|
||||
Assert.assertEquals(0, parts[2]);
|
||||
assertEquals(1, parts[0]);
|
||||
assertEquals(1, parts[1]);
|
||||
assertEquals(0, parts[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,40 +190,40 @@ public class StringUtilsTest {
|
||||
@Test
|
||||
public void testGetTimeParts_negative() {
|
||||
int[] parts = StringUtils.getTimeParts(-61000);
|
||||
Assert.assertEquals(-1, parts[0]);
|
||||
Assert.assertEquals(-1, parts[1]);
|
||||
Assert.assertEquals(0, parts[2]);
|
||||
assertEquals(-1, parts[0]);
|
||||
assertEquals(-1, parts[1]);
|
||||
assertEquals(0, parts[2]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatDecimal() {
|
||||
Assert.assertEquals("0", StringUtils.formatDecimal(0.0, 0));
|
||||
Assert.assertEquals("0", StringUtils.formatDecimal(0.1, 0));
|
||||
Assert.assertEquals("1", StringUtils.formatDecimal(1.1, 0));
|
||||
Assert.assertEquals("10", StringUtils.formatDecimal(10, 0));
|
||||
Assert.assertEquals("10", StringUtils.formatDecimal(10.1, 0));
|
||||
Assert.assertEquals("0", StringUtils.formatDecimal(-0.1, 0));
|
||||
assertEquals("0", StringUtils.formatDecimal(0.0, 0));
|
||||
assertEquals("0", StringUtils.formatDecimal(0.1, 0));
|
||||
assertEquals("1", StringUtils.formatDecimal(1.1, 0));
|
||||
assertEquals("10", StringUtils.formatDecimal(10, 0));
|
||||
assertEquals("10", StringUtils.formatDecimal(10.1, 0));
|
||||
assertEquals("-0", StringUtils.formatDecimal(-0.1, 0));
|
||||
|
||||
Assert.assertEquals("0", StringUtils.formatDecimal(0.0, 2));
|
||||
Assert.assertEquals("0.1", StringUtils.formatDecimal(0.1, 2));
|
||||
Assert.assertEquals("1.1", StringUtils.formatDecimal(1.1, 2));
|
||||
Assert.assertEquals("10", StringUtils.formatDecimal(10, 2));
|
||||
Assert.assertEquals("10.1", StringUtils.formatDecimal(10.1, 2));
|
||||
Assert.assertEquals("10.11", StringUtils.formatDecimal(10.111, 2));
|
||||
Assert.assertEquals("-0.1", StringUtils.formatDecimal(-0.1, 2));
|
||||
assertEquals("0", StringUtils.formatDecimal(0.0, 2));
|
||||
assertEquals("0.1", StringUtils.formatDecimal(0.1, 2));
|
||||
assertEquals("1.1", StringUtils.formatDecimal(1.1, 2));
|
||||
assertEquals("10", StringUtils.formatDecimal(10, 2));
|
||||
assertEquals("10.1", StringUtils.formatDecimal(10.1, 2));
|
||||
assertEquals("10.11", StringUtils.formatDecimal(10.111, 2));
|
||||
assertEquals("-0.1", StringUtils.formatDecimal(-0.1, 2));
|
||||
|
||||
Assert.assertEquals("1", StringUtils.formatDecimal(0.99, 1));
|
||||
assertEquals("1", StringUtils.formatDecimal(0.99, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSpeedParts() {
|
||||
Assert.assertEquals("4:59", StringUtils.getSpeedParts(context, 3.34, true, false).first);
|
||||
Assert.assertEquals("5:00", StringUtils.getSpeedParts(context, 3.33, true, false).first);
|
||||
assertEquals("4:59", StringUtils.getSpeedParts(context, 3.34, true, false).first);
|
||||
assertEquals("5:00", StringUtils.getSpeedParts(context, 3.33, true, false).first);
|
||||
|
||||
Assert.assertEquals("11.99", StringUtils.getSpeedParts(context, 3.33, true, true).first);
|
||||
Assert.assertEquals("7.45", StringUtils.getSpeedParts(context, 3.33, false, true).first);
|
||||
assertEquals("11.9", StringUtils.getSpeedParts(context, 3.31, true, true).first);
|
||||
assertEquals("7.5", StringUtils.getSpeedParts(context, 3.34, false, true).first);
|
||||
|
||||
Assert.assertEquals("min/km", StringUtils.getSpeedParts(context, 0, true, false).second);
|
||||
Assert.assertEquals("min/mi", StringUtils.getSpeedParts(context, 0, false, false).second);
|
||||
assertEquals("min/km", StringUtils.getSpeedParts(context, 0, true, false).second);
|
||||
assertEquals("min/mi", StringUtils.getSpeedParts(context, 0, false, false).second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.content.Context;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -32,6 +31,8 @@ import java.util.Locale;
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests {@link TrackNameUtils}.
|
||||
*
|
||||
@@ -51,7 +52,7 @@ public class TrackNameUtilsTest {
|
||||
@Test
|
||||
public void testTrackName_date_local() {
|
||||
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_local_value));
|
||||
Assert.assertEquals(StringUtils.formatDateTime(CONTEXT, START_TIME), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||
assertEquals(StringUtils.formatDateTime(CONTEXT, START_TIME), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +62,7 @@ public class TrackNameUtilsTest {
|
||||
public void testTrackName_date_iso_8601() {
|
||||
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_iso_8601_value));
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(TrackNameUtils.ISO_8601_FORMAT, Locale.US);
|
||||
Assert.assertEquals(simpleDateFormat.format(new Date(START_TIME)), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||
assertEquals(simpleDateFormat.format(new Date(START_TIME)), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,6 +71,6 @@ public class TrackNameUtilsTest {
|
||||
@Test
|
||||
public void testTrackName_number() {
|
||||
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_number_value));
|
||||
Assert.assertEquals("Track " + TRACK_ID.getId(), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||
assertEquals("Track " + TRACK_ID.getId(), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package de.dennisguse.opentracks.util;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TrackPointUtilsTest {
|
||||
|
||||
@Test
|
||||
@@ -18,7 +19,7 @@ public class TrackPointUtilsTest {
|
||||
TrackPointUtils.fixTime(trackPoint);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(time, trackPoint.getTime());
|
||||
assertEquals(time, trackPoint.getTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -32,7 +33,7 @@ public class TrackPointUtilsTest {
|
||||
TrackPointUtils.fixTime(trackPoint);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(time, trackPoint.getTime(), 1000);
|
||||
assertEquals(time, trackPoint.getTime(), 1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -46,7 +47,7 @@ public class TrackPointUtilsTest {
|
||||
TrackPointUtils.fixTime(trackPoint);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(time, trackPoint.getTime());
|
||||
assertEquals(time, trackPoint.getTime());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,12 +2,13 @@ package de.dennisguse.opentracks.util;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class UUIDUtilsTest {
|
||||
|
||||
@@ -18,6 +19,6 @@ public class UUIDUtilsTest {
|
||||
byte[] bytes = UUIDUtils.toBytes(uuid);
|
||||
UUID output = UUIDUtils.fromBytes(bytes);
|
||||
|
||||
Assert.assertEquals(uuid, output);
|
||||
assertEquals(uuid, output);
|
||||
}
|
||||
}
|
||||
+46
-44
@@ -4,7 +4,6 @@ import android.content.Context;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
@@ -14,6 +13,9 @@ import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class AggregatedStatisticsTest {
|
||||
|
||||
@@ -33,7 +35,7 @@ public class AggregatedStatisticsTest {
|
||||
statistics.setTotalTime(totalTime);
|
||||
statistics.setMovingTime(totalTime);
|
||||
statistics.setTotalDistance(totalDistance);
|
||||
statistics.setTotalElevationGain(50.0);
|
||||
statistics.setTotalElevationGain(50.0f);
|
||||
statistics.setMaxSpeed(50.0); // Resulting max speed
|
||||
statistics.setMaxElevation(1250.0);
|
||||
statistics.setMinElevation(1200.0); // Resulting min elevation
|
||||
@@ -59,13 +61,13 @@ public class AggregatedStatisticsTest {
|
||||
aggregatedStatistics.aggregate(track);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(1, aggregatedStatistics.getCount());
|
||||
Assert.assertNotNull(aggregatedStatistics.get(biking));
|
||||
Assert.assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
||||
assertEquals(1, aggregatedStatistics.getCount());
|
||||
assertNotNull(aggregatedStatistics.get(biking));
|
||||
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
||||
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -82,7 +84,7 @@ public class AggregatedStatisticsTest {
|
||||
aggregatedStatistics.aggregate(track);
|
||||
|
||||
// then
|
||||
Assert.assertNotNull(aggregatedStatistics.get(mountainBiking));
|
||||
assertNotNull(aggregatedStatistics.get(mountainBiking));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,7 +101,7 @@ public class AggregatedStatisticsTest {
|
||||
aggregatedStatistics.aggregate(track);
|
||||
|
||||
// then
|
||||
Assert.assertNotNull(aggregatedStatistics.get(trailRunning));
|
||||
assertNotNull(aggregatedStatistics.get(trailRunning));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -120,13 +122,13 @@ public class AggregatedStatisticsTest {
|
||||
aggregatedStatistics.aggregate(tracks[1]); // biking activity 2.
|
||||
|
||||
// then
|
||||
Assert.assertEquals(1, aggregatedStatistics.getCount());
|
||||
Assert.assertNotNull(aggregatedStatistics.get(biking));
|
||||
Assert.assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
|
||||
assertEquals(1, aggregatedStatistics.getCount());
|
||||
assertNotNull(aggregatedStatistics.get(biking));
|
||||
assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
|
||||
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime * 2L, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime * 2L, statistics2.getMovingTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -152,30 +154,30 @@ public class AggregatedStatisticsTest {
|
||||
aggregatedStatistics.aggregate(tracks[2]); // biking activity 3.
|
||||
|
||||
// then
|
||||
Assert.assertEquals(3, aggregatedStatistics.getCount());
|
||||
Assert.assertNotNull(aggregatedStatistics.get(biking));
|
||||
Assert.assertNotNull(aggregatedStatistics.get(running));
|
||||
Assert.assertNotNull(aggregatedStatistics.get(walking));
|
||||
Assert.assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
||||
Assert.assertEquals(1, aggregatedStatistics.get(running).getCountTracks());
|
||||
Assert.assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
|
||||
assertEquals(3, aggregatedStatistics.getCount());
|
||||
assertNotNull(aggregatedStatistics.get(biking));
|
||||
assertNotNull(aggregatedStatistics.get(running));
|
||||
assertNotNull(aggregatedStatistics.get(walking));
|
||||
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
||||
assertEquals(1, aggregatedStatistics.get(running).getCountTracks());
|
||||
assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
|
||||
|
||||
{
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
}
|
||||
|
||||
{
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
}
|
||||
|
||||
{
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,46 +214,46 @@ public class AggregatedStatisticsTest {
|
||||
|
||||
// then
|
||||
// 4 sports.
|
||||
Assert.assertEquals(4, aggregatedStatistics.getCount());
|
||||
assertEquals(4, aggregatedStatistics.getCount());
|
||||
|
||||
// There is a map for every sport.
|
||||
Assert.assertNotNull(aggregatedStatistics.get(biking));
|
||||
Assert.assertNotNull(aggregatedStatistics.get(running));
|
||||
Assert.assertNotNull(aggregatedStatistics.get(walking));
|
||||
Assert.assertNotNull(aggregatedStatistics.get(driving));
|
||||
assertNotNull(aggregatedStatistics.get(biking));
|
||||
assertNotNull(aggregatedStatistics.get(running));
|
||||
assertNotNull(aggregatedStatistics.get(walking));
|
||||
assertNotNull(aggregatedStatistics.get(driving));
|
||||
|
||||
// Number of tracks by sport.
|
||||
Assert.assertEquals(5, aggregatedStatistics.get(biking).getCountTracks()); // Biking.
|
||||
Assert.assertEquals(2, aggregatedStatistics.get(running).getCountTracks()); // Running.
|
||||
Assert.assertEquals(2, aggregatedStatistics.get(walking).getCountTracks()); // Walking.
|
||||
Assert.assertEquals(1, aggregatedStatistics.get(driving).getCountTracks()); // Driving.
|
||||
assertEquals(5, aggregatedStatistics.get(biking).getCountTracks()); // Biking.
|
||||
assertEquals(2, aggregatedStatistics.get(running).getCountTracks()); // Running.
|
||||
assertEquals(2, aggregatedStatistics.get(walking).getCountTracks()); // Walking.
|
||||
assertEquals(1, aggregatedStatistics.get(driving).getCountTracks()); // Driving.
|
||||
|
||||
// Biking.
|
||||
{
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance * 5, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime * 5, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance * 5, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime * 5, statistics2.getMovingTime());
|
||||
}
|
||||
|
||||
// Running.
|
||||
{
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime * 2, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime * 2, statistics2.getMovingTime());
|
||||
}
|
||||
|
||||
// Walking.
|
||||
{
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime * 2, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime * 2, statistics2.getMovingTime());
|
||||
}
|
||||
|
||||
// Driving.
|
||||
{
|
||||
TrackStatistics statistics2 = aggregatedStatistics.get(driving).getTrackStatistics();
|
||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
||||
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||
assertEquals(totalTime, statistics2.getMovingTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
package de.dennisguse.opentracks.viewmodels;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class IntervalStatisticsTest {
|
||||
|
||||
private static final String TAG = IntervalStatisticsTest.class.getSimpleName();
|
||||
|
||||
private List<TrackPoint> buildTrackPoints(int numberOfTrackPoints) {
|
||||
Pair<Track, TrackPoint[]> pair = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), numberOfTrackPoints);
|
||||
return Arrays.asList(pair.second);
|
||||
}
|
||||
|
||||
private TrackStatistics buildTrackStatistics(List<TrackPoint> trackPoints) {
|
||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(trackPoints.get(0).getTime());
|
||||
for (TrackPoint tp : trackPoints) {
|
||||
trackStatisticsUpdater.addTrackPoint(tp, 0);
|
||||
}
|
||||
return trackStatisticsUpdater.getTrackStatistics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
|
||||
*/
|
||||
@Test
|
||||
public void testBuild_1() {
|
||||
// With 50 points and interval distance of 1000m.
|
||||
|
||||
// given
|
||||
List<TrackPoint> trackPoints = buildTrackPoints(50);
|
||||
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
|
||||
float distanceInterval = 1000f;
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||
|
||||
// when and then
|
||||
whenAndThen(trackPoints, trackStatistics, distanceInterval, intervalStatistics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
|
||||
*/
|
||||
@Test
|
||||
public void testBuild_2() {
|
||||
// With 200 points and interval distance of 1000m.
|
||||
|
||||
// given
|
||||
List<TrackPoint> trackPoints = buildTrackPoints(200);
|
||||
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
|
||||
float distanceInterval = 1000f;
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||
|
||||
// when and then
|
||||
whenAndThen(trackPoints, trackStatistics, distanceInterval, intervalStatistics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
|
||||
*/
|
||||
@Test
|
||||
public void testBuild_3() {
|
||||
// With 200 points and interval distance of 3000m.
|
||||
|
||||
// given
|
||||
List<TrackPoint> trackPoints = buildTrackPoints(200);
|
||||
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
|
||||
float distanceInterval = 3000;
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||
|
||||
// when and then
|
||||
whenAndThen(trackPoints, trackStatistics, distanceInterval, intervalStatistics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
|
||||
*/
|
||||
@Test
|
||||
public void testBuild_4() {
|
||||
// With 1000 points and interval distance of 3000m.
|
||||
|
||||
// given
|
||||
List<TrackPoint> trackPoints = buildTrackPoints(1000);
|
||||
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
|
||||
float distanceInterval = 3000;
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||
|
||||
// when and then
|
||||
whenAndThen(trackPoints, trackStatistics, distanceInterval, intervalStatistics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
|
||||
*/
|
||||
@Test
|
||||
public void testBuild_5() {
|
||||
// With 10000 points and interval distance of 1000m.
|
||||
|
||||
// given
|
||||
List<TrackPoint> trackPoints = buildTrackPoints(10000);
|
||||
TrackStatistics trackStatistics = buildTrackStatistics(trackPoints);
|
||||
float distanceInterval = 1000;
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||
|
||||
// when and then
|
||||
whenAndThen(trackPoints, trackStatistics, distanceInterval, intervalStatistics);
|
||||
}
|
||||
|
||||
private void whenAndThen(List<TrackPoint> trackPoints, TrackStatistics trackStatistics, float distanceInterval, IntervalStatistics intervalStatistics) {
|
||||
intervalStatistics.build(trackPoints, distanceInterval);
|
||||
List<IntervalStatistics.Interval> intervalList = intervalStatistics.getIntervalList();
|
||||
double totalDistance = 0d;
|
||||
long totalTime = 0L;
|
||||
for (IntervalStatistics.Interval i : intervalList) {
|
||||
totalDistance += i.getDistance_m();
|
||||
totalTime += ((i.getDistance_m() / i.getSpeed_ms()) * UnitConversions.S_TO_MS);
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals(trackStatistics.getTotalDistance(), totalDistance, 0.01);
|
||||
assertEquals(trackStatistics.getTotalTime() * UnitConversions.MS_TO_S, totalTime * UnitConversions.MS_TO_S, 0.1);
|
||||
assertEquals(intervalList.size(), (int) Math.ceil(trackStatistics.getTotalDistance() / distanceInterval));
|
||||
for (int i = 0; i < intervalList.size() - 1; i++) {
|
||||
assertEquals(intervalList.get(i).getDistance_m(), distanceInterval, 0.001);
|
||||
totalDistance -= intervalList.get(i).getDistance_m();
|
||||
}
|
||||
assertEquals(intervalList.get(intervalList.size() - 1).getDistance_m(), totalDistance, 0.01);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="de.dennisguse.opentracks"
|
||||
android:installLocation="auto">
|
||||
|
||||
@@ -138,7 +137,9 @@ limitations under the License.
|
||||
|
||||
<activity android:name=".TrackEditActivity" />
|
||||
|
||||
<activity android:name=".TrackListActivity">
|
||||
<activity
|
||||
android:name=".TrackListActivity"
|
||||
android:theme="@style/SplashTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
@@ -23,7 +23,7 @@ public class AggregatedStatisticsActivity extends AbstractActivity {
|
||||
final AggregatedStatisticsModel viewModel = new ViewModelProvider(this).get(AggregatedStatisticsModel.class);
|
||||
viewModel.getAggregatedStats().observe(this, aggregatedStatistics -> {
|
||||
if (aggregatedStatistics != null) {
|
||||
adapter = new AggregatedStatisticsAdapter(getApplicationContext(), aggregatedStatistics);
|
||||
adapter = new AggregatedStatisticsAdapter(this, aggregatedStatistics);
|
||||
listView.setAdapter(adapter);
|
||||
}
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
@@ -30,7 +30,7 @@ import androidx.viewpager.widget.ViewPager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
|
||||
import de.dennisguse.opentracks.fragments.MarkerDetailFragment;
|
||||
@@ -48,33 +48,33 @@ public class MarkerDetailActivity extends AbstractActivity implements DeleteMark
|
||||
|
||||
private static final String TAG = MarkerDetailActivity.class.getSimpleName();
|
||||
|
||||
private List<Waypoint.Id> waypointIds;
|
||||
private List<Marker.Id> markerIds;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
|
||||
Waypoint.Id waypointId = getIntent().getParcelableExtra(EXTRA_MARKER_ID);
|
||||
if (waypointId == null) {
|
||||
Marker.Id markerId = getIntent().getParcelableExtra(EXTRA_MARKER_ID);
|
||||
if (markerId == null) {
|
||||
Log.d(TAG, "invalid marker id");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
||||
Waypoint waypoint = contentProviderUtils.getWaypoint(waypointId);
|
||||
Marker marker = contentProviderUtils.getMarker(markerId);
|
||||
|
||||
waypointIds = new ArrayList<>();
|
||||
markerIds = new ArrayList<>();
|
||||
int markerIndex = -1;
|
||||
|
||||
//TODO Load only waypointIds, not the whole waypoint
|
||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(waypoint.getTrackId(), null, -1)) {
|
||||
//TODO Load only markerIds, not the whole marker
|
||||
try (Cursor cursor = contentProviderUtils.getMarkerCursor(marker.getTrackId(), null, -1)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
Waypoint currentMarker = contentProviderUtils.createWaypoint(cursor);
|
||||
waypointIds.add(currentMarker.getId());
|
||||
if (waypointId.equals(currentMarker.getId())) {
|
||||
markerIndex = waypointIds.size() - 1;
|
||||
Marker currentMarker = contentProviderUtils.createMarker(cursor);
|
||||
markerIds.add(currentMarker.getId());
|
||||
if (markerId.equals(currentMarker.getId())) {
|
||||
markerIndex = markerIds.size() - 1;
|
||||
}
|
||||
|
||||
cursor.moveToNext();
|
||||
@@ -127,7 +127,7 @@ public class MarkerDetailActivity extends AbstractActivity implements DeleteMark
|
||||
@Override
|
||||
@NonNull
|
||||
public Fragment getItem(int position) {
|
||||
return MarkerDetailFragment.newInstance(waypointIds.get(position));
|
||||
return MarkerDetailFragment.newInstance(markerIds.get(position));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -138,7 +138,7 @@ public class MarkerDetailActivity extends AbstractActivity implements DeleteMark
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return waypointIds.size();
|
||||
return markerIds.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,18 +32,19 @@ import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
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.services.TrackRecordingServiceConnection;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
@@ -67,7 +68,7 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
private static final String TAG = MarkerEditActivity.class.getSimpleName();
|
||||
private Track.Id trackId;
|
||||
private TrackRecordingServiceConnection trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
||||
private Waypoint waypoint;
|
||||
private Marker marker;
|
||||
|
||||
private MenuItem insertPhotoMenuItem;
|
||||
private MenuItem insertGalleryImgMenuItem;
|
||||
@@ -76,35 +77,35 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
private boolean hasCamera;
|
||||
|
||||
// UI elements
|
||||
private EditText waypointName;
|
||||
private AutoCompleteTextView waypointMarkerType;
|
||||
private EditText waypointDescription;
|
||||
private ImageView waypointPhoto;
|
||||
private ImageView waypointDeletePhotoBtn;
|
||||
private TextInputEditText markerName;
|
||||
private AutoCompleteTextView markerType;
|
||||
private TextInputEditText markerDescription;
|
||||
private ImageView markerPhoto;
|
||||
private ImageView markerDeletePhotoBtn;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID);
|
||||
Waypoint.Id waypointId = getIntent().getParcelableExtra(EXTRA_MARKER_ID);
|
||||
Marker.Id markerId = getIntent().getParcelableExtra(EXTRA_MARKER_ID);
|
||||
|
||||
hasCamera = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
|
||||
|
||||
// Setup UI elements
|
||||
waypointName = findViewById(R.id.marker_edit_waypoint_name);
|
||||
waypointMarkerType = findViewById(R.id.marker_edit_waypoint_marker_type);
|
||||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.waypoint_types, android.R.layout.simple_dropdown_item_1line);
|
||||
waypointMarkerType.setAdapter(adapter);
|
||||
waypointDescription = findViewById(R.id.marker_edit_waypoint_description);
|
||||
waypointPhoto = findViewById(R.id.marker_edit_waypoint_photo);
|
||||
markerName = findViewById(R.id.marker_edit_name);
|
||||
markerType = findViewById(R.id.marker_edit_marker_type);
|
||||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.marker_types, android.R.layout.simple_dropdown_item_1line);
|
||||
markerType.setAdapter(adapter);
|
||||
markerDescription = findViewById(R.id.marker_edit_description);
|
||||
markerPhoto = findViewById(R.id.marker_edit_photo);
|
||||
|
||||
waypointDeletePhotoBtn = findViewById(R.id.marker_edit_waypoint_photo_delete);
|
||||
waypointDeletePhotoBtn.setOnClickListener(v -> {
|
||||
if (waypoint != null && waypoint.hasPhoto()) {
|
||||
waypoint.setPhotoUrl(null);
|
||||
markerDeletePhotoBtn = findViewById(R.id.marker_edit_photo_delete);
|
||||
markerDeletePhotoBtn.setOnClickListener(v -> {
|
||||
if (marker != null && marker.hasPhoto()) {
|
||||
marker.setPhotoUrl(null);
|
||||
}
|
||||
waypointPhoto.setImageBitmap(null);
|
||||
markerPhoto.setImageBitmap(null);
|
||||
photoUri = null;
|
||||
hideAndShowOptions();
|
||||
});
|
||||
@@ -112,7 +113,7 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
Button cancel = findViewById(R.id.marker_edit_cancel);
|
||||
cancel.setOnClickListener(v -> finish());
|
||||
|
||||
final boolean isNewMarker = waypointId == null;
|
||||
final boolean isNewMarker = markerId == null;
|
||||
|
||||
setTitle(isNewMarker ? R.string.menu_insert_marker : R.string.menu_edit);
|
||||
Button done = findViewById(R.id.marker_edit_done);
|
||||
@@ -127,37 +128,37 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
});
|
||||
|
||||
if (isNewMarker) {
|
||||
int nextWaypointNumber = trackId == null ? -1 : new ContentProviderUtils(this).getNextWaypointNumber(trackId);
|
||||
if (nextWaypointNumber == -1) {
|
||||
nextWaypointNumber = 0;
|
||||
int nextMarkerNumber = trackId == null ? -1 : new ContentProviderUtils(this).getNextMarkerNumber(trackId);
|
||||
if (nextMarkerNumber == -1) {
|
||||
nextMarkerNumber = 0;
|
||||
}
|
||||
waypointName.setText(getString(R.string.marker_name_format, nextWaypointNumber));
|
||||
waypointName.selectAll();
|
||||
waypointMarkerType.setText("");
|
||||
waypointDescription.setText("");
|
||||
markerName.setText(getString(R.string.marker_name_format, nextMarkerNumber));
|
||||
markerName.selectAll();
|
||||
markerType.setText("");
|
||||
markerDescription.setText("");
|
||||
} else {
|
||||
waypoint = new ContentProviderUtils(this).getWaypoint(waypointId);
|
||||
if (waypoint == null) {
|
||||
Log.d(TAG, "waypoint is null");
|
||||
marker = new ContentProviderUtils(this).getMarker(markerId);
|
||||
if (marker == null) {
|
||||
Log.d(TAG, "marker is null");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
waypointName.setText(waypoint.getName());
|
||||
waypointMarkerType.setText(waypoint.getCategory());
|
||||
waypointDescription.setText(waypoint.getDescription());
|
||||
if (waypoint.hasPhoto()) {
|
||||
photoUri = waypoint.getPhotoURI();
|
||||
markerName.setText(marker.getName());
|
||||
markerType.setText(marker.getCategory());
|
||||
markerDescription.setText(marker.getDescription());
|
||||
if (marker.hasPhoto()) {
|
||||
photoUri = marker.getPhotoURI();
|
||||
}
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
photoUri = savedInstanceState.getParcelable(BUNDLE_PHOTO_URI);
|
||||
if (waypoint != null) {
|
||||
waypoint.setPhotoUrl(photoUri != null ? photoUri.toString() : null);
|
||||
if (marker != null) {
|
||||
marker.setPhotoUrl(photoUri != null ? photoUri.toString() : null);
|
||||
}
|
||||
}
|
||||
if (photoUri != null) {
|
||||
setWaypointImageView(photoUri);
|
||||
setMarkerImageView(photoUri);
|
||||
}
|
||||
|
||||
hideAndShowOptions();
|
||||
@@ -202,10 +203,10 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.marker_edit_insert_photo:
|
||||
createWaypointWithPicture();
|
||||
createMarkerWithPicture();
|
||||
return true;
|
||||
case R.id.marker_edit_insert_gallery_img:
|
||||
createWaypointWithGalleryImage();
|
||||
createMarkerWithGalleryImage();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
@@ -219,7 +220,7 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
Toast.makeText(this, R.string.marker_add_photo_canceled, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
} else if (resultCode == RESULT_OK) {
|
||||
setWaypointImageView(photoUri);
|
||||
setMarkerImageView(photoUri);
|
||||
}
|
||||
} else if (requestCode == GALLERY_IMG_REQUEST_CODE) {
|
||||
if (resultCode == RESULT_CANCELED) {
|
||||
@@ -233,7 +234,7 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
FileUtils.copy(srcFd, dstFile);
|
||||
|
||||
photoUri = FileUtils.getUriForFile(this, dstFile);
|
||||
setWaypointImageView(photoUri);
|
||||
setMarkerImageView(photoUri);
|
||||
} catch(Exception e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
Toast.makeText(this, R.string.marker_add_canceled, Toast.LENGTH_LONG).show();
|
||||
@@ -250,31 +251,26 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
* If a photo is set then one's options are shown, otherwise another ones are shown.
|
||||
*/
|
||||
private void hideAndShowOptions() {
|
||||
boolean isPhotoSet = (waypoint != null && waypoint.hasPhoto()) || photoUri != null;
|
||||
boolean isPhotoSet = (marker != null && marker.hasPhoto()) || photoUri != null;
|
||||
if (insertPhotoMenuItem != null && insertGalleryImgMenuItem != null) {
|
||||
insertPhotoMenuItem.setVisible(!isPhotoSet);
|
||||
insertGalleryImgMenuItem.setVisible(!isPhotoSet);
|
||||
}
|
||||
waypointDeletePhotoBtn.setVisibility(isPhotoSet ? View.VISIBLE : View.GONE);
|
||||
markerDeletePhotoBtn.setVisibility(isPhotoSet ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the trackId. If trackId == -1 then get it from waypoint object.
|
||||
* Returns the trackId; either from track or marker.
|
||||
*/
|
||||
private Track.Id getTrackId() {
|
||||
return trackId == null ? waypoint.getTrackId() : trackId;
|
||||
return trackId == null ? marker.getTrackId() : trackId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ImageView waypointPhoto with the uri photo.
|
||||
*
|
||||
* @param uri the uri photo.
|
||||
*/
|
||||
private void setWaypointImageView(@NonNull Uri uri) {
|
||||
private void setMarkerImageView(@NonNull Uri uri) {
|
||||
try (ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "r")) {
|
||||
FileDescriptor fd = pfd.getFileDescriptor();
|
||||
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd);
|
||||
waypointPhoto.setImageBitmap(bitmap);
|
||||
markerPhoto.setImageBitmap(bitmap);
|
||||
hideAndShowOptions();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
@@ -282,31 +278,31 @@ public class MarkerEditActivity extends AbstractActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void createWaypointWithPicture() {
|
||||
private void createMarkerWithPicture() {
|
||||
Pair<Intent, Uri> intentAndPhotoUri = IntentUtils.createTakePictureIntent(this, getTrackId());
|
||||
photoUri = intentAndPhotoUri.second;
|
||||
startActivityForResult(intentAndPhotoUri.first, CAMERA_REQUEST_CODE);
|
||||
}
|
||||
|
||||
private void createWaypointWithGalleryImage() {
|
||||
private void createMarkerWithGalleryImage() {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
startActivityForResult(intent, GALLERY_IMG_REQUEST_CODE);
|
||||
}
|
||||
|
||||
private void addMarker() {
|
||||
trackRecordingServiceConnection.addMarker(this,
|
||||
waypointName.getText().toString(),
|
||||
waypointMarkerType.getText().toString(),
|
||||
waypointDescription.getText().toString(),
|
||||
markerName.getText().toString(),
|
||||
markerType.getText().toString(),
|
||||
markerDescription.getText().toString(),
|
||||
photoUri != null ? photoUri.toString() : null);
|
||||
}
|
||||
|
||||
private void saveMarker() {
|
||||
waypoint.setName(waypointName.getText().toString());
|
||||
waypoint.setCategory(waypointMarkerType.getText().toString());
|
||||
waypoint.setDescription(waypointDescription.getText().toString());
|
||||
waypoint.setPhotoUrl(photoUri != null ? photoUri.toString() : null);
|
||||
marker.setName(markerName.getText().toString());
|
||||
marker.setCategory(markerType.getText().toString());
|
||||
marker.setDescription(markerDescription.getText().toString());
|
||||
marker.setPhotoUrl(photoUri != null ? photoUri.toString() : null);
|
||||
|
||||
new ContentProviderUtils(this).updateWaypoint(this, waypoint);
|
||||
new ContentProviderUtils(this).updateMarker(this, marker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,9 @@ import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.app.LoaderManager.LoaderCallbacks;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
|
||||
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
|
||||
@@ -124,19 +124,19 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
||||
listView.setEmptyView(findViewById(R.id.marker_list_empty));
|
||||
listView.setOnItemClickListener((parent, view, position, id) -> {
|
||||
Intent intent = IntentUtils.newIntent(MarkerListActivity.this, MarkerDetailActivity.class)
|
||||
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, new Waypoint.Id(id));
|
||||
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, new Marker.Id(id));
|
||||
startActivity(intent);
|
||||
});
|
||||
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) {
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
int nameIndex = cursor.getColumnIndex(WaypointsColumns.NAME);
|
||||
int timeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.TIME);
|
||||
int categoryIndex = cursor.getColumnIndex(WaypointsColumns.CATEGORY);
|
||||
int descriptionIndex = cursor.getColumnIndex(WaypointsColumns.DESCRIPTION);
|
||||
int photoUrlIndex = cursor.getColumnIndex(WaypointsColumns.PHOTOURL);
|
||||
int latitudeIndex = cursor.getColumnIndex(WaypointsColumns.LATITUDE);
|
||||
int longitudeIndex = cursor.getColumnIndex(WaypointsColumns.LONGITUDE);
|
||||
int nameIndex = cursor.getColumnIndex(MarkerColumns.NAME);
|
||||
int timeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.TIME);
|
||||
int categoryIndex = cursor.getColumnIndex(MarkerColumns.CATEGORY);
|
||||
int descriptionIndex = cursor.getColumnIndex(MarkerColumns.DESCRIPTION);
|
||||
int photoUrlIndex = cursor.getColumnIndex(MarkerColumns.PHOTOURL);
|
||||
int latitudeIndex = cursor.getColumnIndex(MarkerColumns.LATITUDE);
|
||||
int longitudeIndex = cursor.getColumnIndex(MarkerColumns.LONGITUDE);
|
||||
|
||||
int iconId = MarkerUtils.ICON_ID;
|
||||
String name = cursor.getString(nameIndex);
|
||||
@@ -158,7 +158,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
||||
@NonNull
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||
return ContentProviderUtils.getWaypointsLoader(MarkerListActivity.this, track != null ? track.getId() : null);
|
||||
return ContentProviderUtils.getMarkersLoader(MarkerListActivity.this, track != null ? track.getId() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -229,35 +229,35 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
||||
/**
|
||||
* Handles a context item selection.
|
||||
*
|
||||
* @param itemId the menu item id
|
||||
* @param longWaypointIds the marker ids
|
||||
* @param itemId the menu item id
|
||||
* @param longMarkerds the marker ids
|
||||
* @return true if handled.
|
||||
*/
|
||||
private boolean handleContextItem(int itemId, long... longWaypointIds) {
|
||||
Waypoint.Id[] waypointIds = new Waypoint.Id[longWaypointIds.length];
|
||||
for (int i = 0; i < longWaypointIds.length; i++) {
|
||||
waypointIds[i] = new Waypoint.Id(longWaypointIds[i]);
|
||||
private boolean handleContextItem(int itemId, long... longMarkerds) {
|
||||
Marker.Id[] markerIds = new Marker.Id[longMarkerds.length];
|
||||
for (int i = 0; i < longMarkerds.length; i++) {
|
||||
markerIds[i] = new Marker.Id(longMarkerds[i]);
|
||||
}
|
||||
|
||||
Intent intent;
|
||||
switch (itemId) {
|
||||
case R.id.list_context_menu_show_on_map:
|
||||
if (waypointIds.length == 1) {
|
||||
IntentUtils.showCoordinateOnMap(this, contentProviderUtils.getWaypoint(waypointIds[0]));
|
||||
if (markerIds.length == 1) {
|
||||
IntentUtils.showCoordinateOnMap(this, contentProviderUtils.getMarker(markerIds[0]));
|
||||
}
|
||||
return true;
|
||||
case R.id.list_context_menu_edit:
|
||||
if (waypointIds.length == 1) {
|
||||
if (markerIds.length == 1) {
|
||||
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
|
||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, waypointIds[0]);
|
||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerIds[0]);
|
||||
startActivity(intent);
|
||||
}
|
||||
return true;
|
||||
case R.id.list_context_menu_delete:
|
||||
if (waypointIds.length > 1 && waypointIds.length == listView.getCount()) {
|
||||
waypointIds = null;
|
||||
if (markerIds.length > 1 && markerIds.length == listView.getCount()) {
|
||||
markerIds = null;
|
||||
}
|
||||
DeleteMarkerDialogFragment.showDialog(getSupportFragmentManager(), waypointIds);
|
||||
DeleteMarkerDialogFragment.showDialog(getSupportFragmentManager(), markerIds);
|
||||
return true;
|
||||
case R.id.list_context_menu_select_all:
|
||||
for (int i = 0; i < listView.getCount(); i++) {
|
||||
|
||||
@@ -41,8 +41,8 @@ import java.util.SortedSet;
|
||||
import de.dennisguse.opentracks.content.SearchEngine;
|
||||
import de.dennisguse.opentracks.content.SearchEngine.ScoredResult;
|
||||
import de.dennisguse.opentracks.content.SearchEngine.SearchQuery;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
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.fragments.ConfirmDeleteDialogFragment;
|
||||
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
|
||||
@@ -204,7 +204,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
||||
listView.setOnItemClickListener((parent, view, position, id) -> {
|
||||
Map<String, Object> item = arrayAdapter.getItem(position);
|
||||
Track.Id trackId = (Track.Id) item.get(TRACK_ID_FIELD);
|
||||
Long markerId = (Long) item.get(MARKER_ID_FIELD);
|
||||
Marker.Id markerId = (Marker.Id) item.get(MARKER_ID_FIELD);
|
||||
Intent intent = IntentUtils.newIntent(SearchListActivity.this, TrackRecordedActivity.class);
|
||||
if (markerId != null) {
|
||||
intent = intent.putExtra(TrackRecordedActivity.EXTRA_MARKER_ID, markerId);
|
||||
@@ -271,7 +271,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
||||
}
|
||||
Map<String, Object> item = arrayAdapter.getItem(positions[0]);
|
||||
Track.Id trackId = (Track.Id) item.get(TRACK_ID_FIELD);
|
||||
Waypoint.Id waypointId = (Waypoint.Id) item.get(MARKER_ID_FIELD);
|
||||
Marker.Id markerId = (Marker.Id) item.get(MARKER_ID_FIELD);
|
||||
Intent intent;
|
||||
switch (itemId) {
|
||||
case R.id.list_context_menu_show_on_map:
|
||||
@@ -283,9 +283,9 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.list_context_menu_edit:
|
||||
if (waypointId != null) {
|
||||
if (markerId != null) {
|
||||
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
|
||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, waypointId);
|
||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
|
||||
} else {
|
||||
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
|
||||
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
|
||||
@@ -296,8 +296,8 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
||||
finish();
|
||||
return true;
|
||||
case R.id.list_context_menu_delete:
|
||||
if (waypointId != null) {
|
||||
DeleteMarkerDialogFragment.showDialog(getSupportFragmentManager(), waypointId);
|
||||
if (markerId != null) {
|
||||
DeleteMarkerDialogFragment.showDialog(getSupportFragmentManager(), markerId);
|
||||
} else {
|
||||
deleteTracks(trackId);
|
||||
}
|
||||
@@ -349,30 +349,24 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
||||
* @return a list of result maps
|
||||
*/
|
||||
private List<Map<String, Object>> prepareResultsforDisplay(Collection<ScoredResult> scoredResults) {
|
||||
//TODO Replace use of map<string, object>, but rather provide Track or Waypoint directly.
|
||||
//TODO Replace use of map<string, object>, but rather provide Track or Marker directly.
|
||||
ArrayList<Map<String, Object>> output = new ArrayList<>(scoredResults.size());
|
||||
for (ScoredResult result : scoredResults) {
|
||||
if (result.track != null) {
|
||||
output.add(prepareTrackForDisplay(result.track));
|
||||
} else {
|
||||
output.add(prepareMarkerForDisplay(result.waypoint));
|
||||
output.add(prepareMarkerForDisplay(result.marker));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a marker for display by filling in a result map.
|
||||
*
|
||||
* @param waypoint the marker
|
||||
* @return the result map
|
||||
*/
|
||||
private Map<String, Object> prepareMarkerForDisplay(Waypoint waypoint) {
|
||||
private Map<String, Object> prepareMarkerForDisplay(Marker marker) {
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
|
||||
//TODO: It may be more appropriate to obtain the track name as a join in the retrieval phase of the searchable.
|
||||
String trackName = null;
|
||||
Track.Id trackId = waypoint.getTrackId();
|
||||
Track.Id trackId = marker.getTrackId();
|
||||
if (!trackId.isValid()) {
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
if (track != null) {
|
||||
@@ -384,20 +378,20 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
||||
resultMap.put(IS_PAUSED_FIELD, true);
|
||||
resultMap.put(ICON_ID_FIELD, MarkerUtils.ICON_ID);
|
||||
resultMap.put(ICON_CONTENT_DESCRIPTION_ID_FIELD, R.string.image_marker);
|
||||
resultMap.put(NAME_FIELD, waypoint.getName());
|
||||
resultMap.put(NAME_FIELD, marker.getName());
|
||||
// Display the marker's track name in the total time field
|
||||
resultMap.put(TOTAL_TIME_FIELD, trackName == null ? null : getString(R.string.search_list_marker_track_location, trackName));
|
||||
resultMap.put(TOTAL_DISTANCE_FIELD, null);
|
||||
resultMap.put(MARKER_COUNT_FIELD, 0);
|
||||
resultMap.put(START_TIME_FIELD, waypoint.getLocation().getTime());
|
||||
resultMap.put(CATEGORY_FIELD, waypoint.getCategory());
|
||||
resultMap.put(DESCRIPTION_FIELD, waypoint.getDescription());
|
||||
resultMap.put(PHOTO_URL_FIELD, waypoint.getPhotoUrl());
|
||||
resultMap.put(TRACK_ID_FIELD, waypoint.getTrackId());
|
||||
resultMap.put(MARKER_ID_FIELD, waypoint.getId());
|
||||
resultMap.put(START_TIME_FIELD, marker.getLocation().getTime());
|
||||
resultMap.put(CATEGORY_FIELD, marker.getCategory());
|
||||
resultMap.put(DESCRIPTION_FIELD, marker.getDescription());
|
||||
resultMap.put(PHOTO_URL_FIELD, marker.getPhotoUrl());
|
||||
resultMap.put(TRACK_ID_FIELD, marker.getTrackId());
|
||||
resultMap.put(MARKER_ID_FIELD, marker.getId());
|
||||
|
||||
resultMap.put(MARKER_LATITUDE_FIELD, waypoint.getLocation().getLatitude());
|
||||
resultMap.put(MARKER_LONGITUDE_FIELD, waypoint.getLocation().getLongitude());
|
||||
resultMap.put(MARKER_LATITUDE_FIELD, marker.getLocation().getLatitude());
|
||||
resultMap.put(MARKER_LONGITUDE_FIELD, marker.getLocation().getLongitude());
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
@@ -415,14 +409,14 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
||||
String icon = track.getIcon();
|
||||
String category = icon != null && !icon.equals("") ? null : track.getCategory();
|
||||
|
||||
resultMap.put(IS_RECORDING_FIELD, track.getId() == recordingTrackId);
|
||||
resultMap.put(IS_RECORDING_FIELD, track.getId().equals(recordingTrackId));
|
||||
resultMap.put(IS_PAUSED_FIELD, recordingTrackPaused);
|
||||
resultMap.put(ICON_ID_FIELD, TrackIconUtils.getIconDrawable(icon));
|
||||
resultMap.put(ICON_CONTENT_DESCRIPTION_ID_FIELD, R.string.image_track);
|
||||
resultMap.put(NAME_FIELD, track.getName());
|
||||
resultMap.put(TOTAL_TIME_FIELD, StringUtils.formatElapsedTime(trackStatistics.getTotalTime()));
|
||||
resultMap.put(TOTAL_DISTANCE_FIELD, StringUtils.formatDistance(this, trackStatistics.getTotalDistance(), metricUnits));
|
||||
resultMap.put(MARKER_COUNT_FIELD, contentProviderUtils.getWaypointCount(track.getId()));
|
||||
resultMap.put(MARKER_COUNT_FIELD, contentProviderUtils.getMarkerCount(track.getId()));
|
||||
resultMap.put(START_TIME_FIELD, trackStatistics.getStartTime_ms());
|
||||
resultMap.put(CATEGORY_FIELD, category);
|
||||
resultMap.put(DESCRIPTION_FIELD, track.getDescription());
|
||||
|
||||
@@ -11,7 +11,6 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
import java.util.Set;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ShareContentProvider;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.util.IntentDashboardUtils;
|
||||
@@ -31,7 +30,7 @@ public abstract class ShowOnMapProxyActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
Set<Track.Id> trackIds = IntentDashboardUtils.extractTrackIdsFromIntent(getIntent());
|
||||
|
||||
showTrackTrackfileFormat(this, trackFileFormat, trackIds);
|
||||
showTrackfileFormat(this, trackFileFormat, trackIds);
|
||||
|
||||
finish();
|
||||
}
|
||||
@@ -42,14 +41,14 @@ public abstract class ShowOnMapProxyActivity extends AppCompatActivity {
|
||||
* @param context the context
|
||||
* @param trackIds the track ids
|
||||
*/
|
||||
private static void showTrackTrackfileFormat(Context context, TrackFileFormat trackFileFormat, Set<Track.Id> trackIds) {
|
||||
private static void showTrackfileFormat(Context context, TrackFileFormat trackFileFormat, Set<Track.Id> trackIds) {
|
||||
if (trackIds.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra(TrackPointsColumns.TRACKID, trackIds.toArray(new Track.Id[0])[0]);
|
||||
|
||||
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, "SharingTrack", trackFileFormat);
|
||||
intent.setDataAndType(uriAndMime.first, uriAndMime.second);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.util.Log;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import de.dennisguse.opentracks.util.ActivityUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
/**
|
||||
@@ -32,6 +33,8 @@ public class Startup extends Application {
|
||||
PreferencesUtils.setString(this, R.string.stats_units_key, statsUnits);
|
||||
}
|
||||
|
||||
ActivityUtils.applyNightMode(this);
|
||||
|
||||
//TODO Workaround to reset recordingTrackId on app startup as the TrackRecordingService (likely) crashed.
|
||||
if (PreferencesUtils.isRecording(this)) {
|
||||
Log.e(TAG, "Reset recordingTrackId; likely the TrackRecordingService crashed.");
|
||||
|
||||
@@ -24,11 +24,12 @@ import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
||||
@@ -55,10 +56,10 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
||||
private Track track;
|
||||
private String iconValue;
|
||||
|
||||
private EditText nameEditText;
|
||||
private TextInputEditText nameEditText;
|
||||
private AutoCompleteTextView activityType;
|
||||
private Spinner activityTypeIcon;
|
||||
private EditText description;
|
||||
private TextInputEditText description;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
@@ -75,7 +76,7 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
||||
contentProviderUtils = new ContentProviderUtils(this);
|
||||
track = contentProviderUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
Log.e(TAG, "No track for " + trackId);
|
||||
Log.e(TAG, "No track for " + trackId.getId());
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -214,6 +214,9 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
// Reset theme after splash
|
||||
setTheme(R.style.ThemeCustom);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
gpsStatusValue = GpsStatusValue.GPS_NONE;
|
||||
@@ -263,13 +266,13 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
||||
int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION);
|
||||
|
||||
Track.Id trackId = new Track.Id(cursor.getLong(idIndex));
|
||||
boolean isRecording = trackId == recordingTrackId;
|
||||
boolean isRecording = trackId.equals(recordingTrackId);
|
||||
String icon = cursor.getString(iconIndex);
|
||||
int iconId = TrackIconUtils.getIconDrawable(icon);
|
||||
String name = cursor.getString(nameIndex);
|
||||
String totalTime = StringUtils.formatElapsedTime(cursor.getLong(totalTimeIndex));
|
||||
String totalDistance = StringUtils.formatDistance(TrackListActivity.this, cursor.getDouble(totalDistanceIndex), metricUnits);
|
||||
int markerCount = contentProviderUtils.getWaypointCount(trackId);
|
||||
int markerCount = contentProviderUtils.getMarkerCount(trackId);
|
||||
long startTime = cursor.getLong(startTimeIndex);
|
||||
String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex);
|
||||
String description = cursor.getString(descriptionIndex);
|
||||
|
||||
@@ -24,18 +24,20 @@ import android.view.MenuItem;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import de.dennisguse.opentracks.content.TrackDataHub;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
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.fragments.ChartFragment;
|
||||
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
||||
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
||||
import de.dennisguse.opentracks.fragments.IntervalsFragment;
|
||||
import de.dennisguse.opentracks.fragments.StatisticsRecordedFragment;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||
import de.dennisguse.opentracks.settings.SettingsActivity;
|
||||
@@ -53,11 +55,11 @@ import de.dennisguse.opentracks.util.TrackUtils;
|
||||
*/
|
||||
public class TrackRecordedActivity extends AbstractListActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, ConfirmDeleteDialogFragment.ConfirmDeleteCaller, TrackActivityDataHubInterface {
|
||||
|
||||
private static final String TAG = TrackRecordedActivity.class.getSimpleName();
|
||||
|
||||
public static final String EXTRA_TRACK_ID = "track_id";
|
||||
public static final String EXTRA_MARKER_ID = "marker_id";
|
||||
|
||||
private static final String TAG = TrackRecordedActivity.class.getSimpleName();
|
||||
|
||||
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
|
||||
|
||||
// The following are set in onCreate.
|
||||
@@ -65,7 +67,6 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
||||
private TrackDataHub trackDataHub;
|
||||
private ViewPager pager;
|
||||
|
||||
// From intent.
|
||||
private Track.Id trackId;
|
||||
|
||||
@Override
|
||||
@@ -77,42 +78,8 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
||||
|
||||
trackDataHub = new TrackDataHub(this);
|
||||
|
||||
FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager(), 1) {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return new StatisticsRecordedFragment();
|
||||
case 1:
|
||||
return ChartFragment.newInstance(false);
|
||||
case 2:
|
||||
return ChartFragment.newInstance(true);
|
||||
default:
|
||||
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return getString(R.string.track_detail_stats_tab);
|
||||
case 1:
|
||||
return getString(R.string.settings_chart_by_time);
|
||||
case 2:
|
||||
return getString(R.string.settings_chart_by_distance);
|
||||
}
|
||||
return "Unknown Tab";
|
||||
}
|
||||
};
|
||||
pager = findViewById(R.id.track_detail_activity_view_pager);
|
||||
pager.setAdapter(adapter);
|
||||
pager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT));
|
||||
TabLayout tabs = findViewById(R.id.track_detail_activity_tablayout);
|
||||
tabs.setupWithViewPager(pager);
|
||||
if (savedInstanceState != null) {
|
||||
@@ -133,7 +100,7 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
||||
// Update UI
|
||||
this.invalidateOptionsMenu();
|
||||
|
||||
if (trackId.isValid()) {
|
||||
if (trackId != null) {
|
||||
trackDataHub.loadTrack(trackId);
|
||||
}
|
||||
}
|
||||
@@ -240,15 +207,15 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
||||
private void handleIntent(Intent intent) {
|
||||
trackId = intent.getParcelableExtra(EXTRA_TRACK_ID);
|
||||
|
||||
Waypoint.Id waypointId = intent.getParcelableExtra(EXTRA_MARKER_ID);
|
||||
if (waypointId != null) {
|
||||
Marker.Id markerId = intent.getParcelableExtra(EXTRA_MARKER_ID);
|
||||
if (markerId != null) {
|
||||
// Use the trackId from the marker
|
||||
Waypoint waypoint = contentProviderUtils.getWaypoint(waypointId);
|
||||
if (waypoint == null) {
|
||||
Marker marker = contentProviderUtils.getMarker(markerId);
|
||||
if (marker == null) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
trackId = waypoint.getTrackId();
|
||||
trackId = marker.getTrackId();
|
||||
}
|
||||
|
||||
if (trackId == null) {
|
||||
@@ -263,8 +230,53 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
||||
|
||||
@Override
|
||||
public void onChooseActivityTypeDone(String iconValue) {
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
String category = getString(TrackIconUtils.getIconActivityType(iconValue));
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
TrackUtils.updateTrack(this, track, null, category, null, contentProviderUtils);
|
||||
}
|
||||
|
||||
private class CustomFragmentPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
public CustomFragmentPagerAdapter(@NonNull FragmentManager fm, int behavior) {
|
||||
super(fm, behavior);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return StatisticsRecordedFragment.newInstance(trackId);
|
||||
case 1:
|
||||
return IntervalsFragment.newInstance(trackId);
|
||||
case 2:
|
||||
return ChartFragment.newInstance(false);
|
||||
case 3:
|
||||
return ChartFragment.newInstance(true);
|
||||
default:
|
||||
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return getString(R.string.track_detail_stats_tab);
|
||||
case 1:
|
||||
return getString(R.string.track_detail_intervals_tab);
|
||||
case 2:
|
||||
return getString(R.string.settings_chart_by_time);
|
||||
case 3:
|
||||
return getString(R.string.settings_chart_by_distance);
|
||||
default:
|
||||
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.fragments.ChartFragment;
|
||||
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
||||
import de.dennisguse.opentracks.fragments.IntervalsFragment;
|
||||
import de.dennisguse.opentracks.fragments.StatisticsRecordingFragment;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
|
||||
@@ -65,6 +66,9 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
// Preferences
|
||||
private boolean recordingTrackPaused;
|
||||
|
||||
// Intervals recording fragment needs Track.Id when the activity creates it.
|
||||
private OnTrackIdListener intervalsListener;
|
||||
|
||||
private final Runnable bindChangedCallback = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -81,6 +85,9 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
if (trackId == null) {
|
||||
// trackId isn't initialized -> leads a new recording.
|
||||
trackId = service.startNewTrack();
|
||||
if (intervalsListener != null) {
|
||||
intervalsListener.onTrackId(trackId);
|
||||
}
|
||||
} else {
|
||||
// trackId is initialized -> resumes the track.
|
||||
service.resumeTrack(trackId);
|
||||
@@ -166,6 +173,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
//Activity was recreated.
|
||||
trackId = savedInstanceState.getParcelable(EXTRA_TRACK_ID);
|
||||
} else {
|
||||
// Resume a track
|
||||
trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID);
|
||||
if (trackId != null && contentProviderUtils.getTrack(trackId) == null) {
|
||||
Log.w(TAG, "TrackId does not exists; cannot continue the recording.");
|
||||
@@ -180,7 +188,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
trackDataHub = new TrackDataHub(this);
|
||||
|
||||
pager = findViewById(R.id.track_detail_activity_view_pager);
|
||||
pager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), 1));
|
||||
pager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT));
|
||||
TabLayout tabs = findViewById(R.id.track_detail_activity_tablayout);
|
||||
tabs.setupWithViewPager(pager);
|
||||
if (savedInstanceState != null) {
|
||||
@@ -372,7 +380,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -380,10 +388,12 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return new StatisticsRecordingFragment();
|
||||
return StatisticsRecordingFragment.newInstance();
|
||||
case 1:
|
||||
return ChartFragment.newInstance(false);
|
||||
return IntervalsFragment.IntervalsRecordingFragment.newInstance(trackId);
|
||||
case 2:
|
||||
return ChartFragment.newInstance(false);
|
||||
case 3:
|
||||
return ChartFragment.newInstance(true);
|
||||
default:
|
||||
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
|
||||
@@ -396,12 +406,25 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
case 0:
|
||||
return getString(R.string.track_detail_stats_tab);
|
||||
case 1:
|
||||
return getString(R.string.settings_chart_by_time);
|
||||
return getString(R.string.track_detail_intervals_tab);
|
||||
case 2:
|
||||
return getString(R.string.settings_chart_by_time);
|
||||
case 3:
|
||||
return getString(R.string.settings_chart_by_distance);
|
||||
default:
|
||||
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnTrackIdListener {
|
||||
void onTrackId(Track.Id trackId);
|
||||
}
|
||||
|
||||
public void setTrackIdListener(OnTrackIdListener listener) {
|
||||
this.intervalsListener = listener;
|
||||
if (trackId != null) {
|
||||
listener.onTrackId(trackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package de.dennisguse.opentracks.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Pair;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||
|
||||
public class IntervalStatisticsAdapter extends ArrayAdapter<IntervalStatistics.Interval> {
|
||||
|
||||
private StackMode stackMode;
|
||||
private boolean metricUnits;
|
||||
private float sumDistance_m;
|
||||
|
||||
public IntervalStatisticsAdapter(Context context, List<IntervalStatistics.Interval> intervalList, StackMode stackMode) {
|
||||
super(context, R.layout.interval_stats_list_item, intervalList);
|
||||
metricUnits = PreferencesUtils.isMetricUnits(context);
|
||||
this.stackMode = stackMode;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View intervalView, @NonNull ViewGroup parent) {
|
||||
int actualPosition = stackMode == StackMode.STACK_FROM_TOP ? position : getCount() - 1 - position;
|
||||
IntervalStatistics.Interval interval = getItem(actualPosition);
|
||||
ViewHolder viewHolder;
|
||||
|
||||
if (intervalView == null) {
|
||||
viewHolder = new ViewHolder();
|
||||
|
||||
intervalView = LayoutInflater.from(getContext()).inflate(R.layout.interval_stats_list_item, parent, false);
|
||||
|
||||
viewHolder.distance = intervalView.findViewById(R.id.interval_item_distance);
|
||||
viewHolder.speed = intervalView.findViewById(R.id.interval_item_speed);
|
||||
viewHolder.pace = intervalView.findViewById(R.id.interval_item_pace);
|
||||
|
||||
intervalView.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) intervalView.getTag();
|
||||
}
|
||||
|
||||
if (actualPosition + 1 == getCount() && actualPosition > 0) {
|
||||
sumDistance_m = actualPosition * getItem(actualPosition - 1).getDistance_m() + interval.getDistance_m();
|
||||
} else {
|
||||
sumDistance_m = (actualPosition + 1) * interval.getDistance_m();
|
||||
}
|
||||
viewHolder.distance.setText(StringUtils.formatDistance(getContext(), sumDistance_m, metricUnits));
|
||||
|
||||
Pair<String, String> speedParts = StringUtils.getSpeedParts(getContext(), interval.getSpeed_ms(), metricUnits, true);
|
||||
viewHolder.speed.setText(speedParts.first + " " + speedParts.second);
|
||||
|
||||
Pair<String, String> paceParts = StringUtils.getSpeedParts(getContext(), interval.getSpeed_ms(), metricUnits, false);
|
||||
viewHolder.pace.setText(paceParts.first + " " + paceParts.second);
|
||||
|
||||
return intervalView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the two modes of list items stacking: from top or from bottom.
|
||||
*/
|
||||
public enum StackMode {
|
||||
STACK_FROM_BOTTOM,
|
||||
STACK_FROM_TOP
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
private TextView distance;
|
||||
private TextView speed;
|
||||
private TextView pace;
|
||||
}
|
||||
}
|
||||
@@ -47,9 +47,9 @@ abstract class ChartValueSeries {
|
||||
private final Paint strokePaint;
|
||||
private final Paint titlePaint;
|
||||
private final Paint markerPaint;
|
||||
private final ExtremityMonitor extremityMonitor;
|
||||
private final NumberFormat numberFormat;
|
||||
private final Path path;
|
||||
private final ExtremityMonitor extremityMonitor = new ExtremityMonitor();
|
||||
private final NumberFormat numberFormat = NumberFormat.getIntegerInstance();
|
||||
private final Path path = new Path();
|
||||
|
||||
private int interval = 1;
|
||||
private int minMarkerValue = 0;
|
||||
@@ -91,17 +91,15 @@ abstract class ChartValueSeries {
|
||||
titlePaint = new Paint(strokePaint);
|
||||
titlePaint.setTextSize(ChartView.MEDIUM_TEXT_SIZE * scale);
|
||||
titlePaint.setTextAlign(Align.CENTER);
|
||||
titlePaint.setStyle(Style.FILL_AND_STROKE);
|
||||
|
||||
markerPaint = new Paint(strokePaint);
|
||||
markerPaint.setTextSize(ChartView.SMALL_TEXT_SIZE * scale);
|
||||
markerPaint.setTextAlign(Align.RIGHT);
|
||||
markerPaint.setStyle(Style.FILL_AND_STROKE);
|
||||
|
||||
// Set stroke paint thickness
|
||||
strokePaint.setStrokeWidth(STROKE_WIDTH);
|
||||
|
||||
extremityMonitor = new ExtremityMonitor();
|
||||
numberFormat = NumberFormat.getIntegerInstance();
|
||||
path = new Path();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,6 @@ package de.dennisguse.opentracks.chart;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Align;
|
||||
@@ -42,11 +41,12 @@ import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.MarkerDetailActivity;
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.stats.ExtremityMonitor;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.MarkerUtils;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
import de.dennisguse.opentracks.util.ThemeUtils;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
|
||||
/**
|
||||
@@ -75,7 +75,7 @@ public class ChartView extends View {
|
||||
private static final int Y_AXIS_OFFSET = 16;
|
||||
|
||||
//TODO Determine from actual size of the used drawable
|
||||
private static final float WAYPOINT_X_ANCHOR = 13f / 48f;
|
||||
private static final float MARKER_X_ANCHOR = 13f / 48f;
|
||||
|
||||
static {
|
||||
X_FRACTION_FORMAT.setMaximumFractionDigits(1);
|
||||
@@ -87,14 +87,15 @@ public class ChartView extends View {
|
||||
private final ChartValueSeries paceSeries;
|
||||
|
||||
private final List<ChartPoint> chartPoints = new ArrayList<>();
|
||||
private final List<Waypoint> waypoints = new ArrayList<>();
|
||||
private final List<Marker> markers = new ArrayList<>();
|
||||
private final ExtremityMonitor xExtremityMonitor = new ExtremityMonitor();
|
||||
private final int backgroundColor;
|
||||
private final Paint axisPaint;
|
||||
private final Paint xAxisMarkerPaint;
|
||||
private final Paint gridPaint;
|
||||
private final Paint markerPaint;
|
||||
private final Drawable pointer;
|
||||
private final Drawable waypointMarker;
|
||||
private final Drawable markerPin;
|
||||
private final int markerWidth;
|
||||
private final int markerHeight;
|
||||
private final Scroller scroller;
|
||||
@@ -150,19 +151,19 @@ public class ChartView extends View {
|
||||
// Check if the y event is within markerHeight of the marker center
|
||||
if (Math.abs(event.getY() - topBorder - spacer - markerHeight / 2f) < markerHeight) {
|
||||
int minDistance = Integer.MAX_VALUE;
|
||||
Waypoint nearestWaypoint = null;
|
||||
synchronized (waypoints) {
|
||||
for (Waypoint waypoint : waypoints) {
|
||||
int distance = Math.abs(getX(getWaypointXValue(waypoint)) - (int) event.getX() - getScrollX());
|
||||
Marker nearestMarker = null;
|
||||
synchronized (markers) {
|
||||
for (Marker marker : markers) {
|
||||
int distance = Math.abs(getX(getMarkerXValue(marker)) - (int) event.getX() - getScrollX());
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
nearestWaypoint = waypoint;
|
||||
nearestMarker = marker;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nearestWaypoint != null && minDistance < markerWidth) {
|
||||
if (nearestMarker != null && minDistance < markerWidth) {
|
||||
Intent intent = IntentUtils.newIntent(getContext(), MarkerDetailActivity.class)
|
||||
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, nearestWaypoint.getId());
|
||||
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, nearestMarker.getId());
|
||||
getContext().startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
@@ -191,7 +192,6 @@ public class ChartView extends View {
|
||||
public ChartView(Context context, final boolean chartByDistance) {
|
||||
super(context);
|
||||
this.chartByDistance = chartByDistance;
|
||||
|
||||
seriesList.add(new ChartValueSeries(context,
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE,
|
||||
@@ -307,11 +307,13 @@ public class ChartView extends View {
|
||||
}
|
||||
});
|
||||
|
||||
backgroundColor = ThemeUtils.getBackgroundColor(context);
|
||||
|
||||
float scale = context.getResources().getDisplayMetrics().density;
|
||||
|
||||
axisPaint = new Paint();
|
||||
axisPaint.setStyle(Style.STROKE);
|
||||
axisPaint.setColor(context.getResources().getColor(android.R.color.black));
|
||||
axisPaint.setStyle(Style.FILL_AND_STROKE);
|
||||
axisPaint.setColor(ThemeUtils.getTextColorPrimary(context));
|
||||
axisPaint.setAntiAlias(true);
|
||||
axisPaint.setTextSize(SMALL_TEXT_SIZE * scale);
|
||||
|
||||
@@ -320,22 +322,21 @@ public class ChartView extends View {
|
||||
|
||||
gridPaint = new Paint();
|
||||
gridPaint.setStyle(Style.STROKE);
|
||||
gridPaint.setColor(context.getResources().getColor(android.R.color.darker_gray));
|
||||
gridPaint.setColor(ThemeUtils.getTextColorSecondary(context));
|
||||
gridPaint.setAntiAlias(false);
|
||||
gridPaint.setPathEffect(new DashPathEffect(new float[]{3, 2}, 0));
|
||||
|
||||
markerPaint = new Paint();
|
||||
markerPaint.setStyle(Style.STROKE);
|
||||
markerPaint.setColor(context.getResources().getColor(android.R.color.darker_gray));
|
||||
markerPaint.setAntiAlias(false);
|
||||
|
||||
pointer = context.getResources().getDrawable(R.drawable.ic_logo_color_24dp);
|
||||
pointer.setBounds(0, 0, pointer.getIntrinsicWidth(), pointer.getIntrinsicHeight());
|
||||
|
||||
waypointMarker = MarkerUtils.getDefaultPhoto(context);
|
||||
markerWidth = waypointMarker.getIntrinsicWidth();
|
||||
markerHeight = waypointMarker.getIntrinsicHeight();
|
||||
waypointMarker.setBounds(0, 0, markerWidth, markerHeight);
|
||||
markerPin = MarkerUtils.getDefaultPhoto(context);
|
||||
markerWidth = markerPin.getIntrinsicWidth();
|
||||
markerHeight = markerPin.getIntrinsicHeight();
|
||||
markerPin.setBounds(0, 0, markerWidth, markerHeight);
|
||||
|
||||
scroller = new Scroller(context);
|
||||
setFocusable(true);
|
||||
@@ -434,15 +435,15 @@ public class ChartView extends View {
|
||||
scrollTo(0, 0);
|
||||
}
|
||||
|
||||
public void addWaypoint(Waypoint waypoint) {
|
||||
synchronized (waypoints) {
|
||||
waypoints.add(waypoint);
|
||||
public void addMarker(Marker marker) {
|
||||
synchronized (markers) {
|
||||
markers.add(marker);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearWaypoints() {
|
||||
synchronized (waypoints) {
|
||||
waypoints.clear();
|
||||
public void clearMarker() {
|
||||
synchronized (markers) {
|
||||
markers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,13 +541,13 @@ public class ChartView extends View {
|
||||
synchronized (chartPoints) {
|
||||
canvas.save();
|
||||
|
||||
canvas.drawColor(Color.WHITE);
|
||||
canvas.drawColor(backgroundColor);
|
||||
|
||||
canvas.save();
|
||||
|
||||
clipToGraphArea(canvas);
|
||||
drawDataSeries(canvas);
|
||||
drawWaypoints(canvas);
|
||||
drawMarker(canvas);
|
||||
drawGrid(canvas);
|
||||
|
||||
canvas.restore();
|
||||
@@ -587,24 +588,19 @@ public class ChartView extends View {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the waypoints.
|
||||
*
|
||||
* @param canvas the canvas
|
||||
*/
|
||||
private void drawWaypoints(Canvas canvas) {
|
||||
synchronized (waypoints) {
|
||||
for (Waypoint waypoint : waypoints) {
|
||||
double xValue = getWaypointXValue(waypoint);
|
||||
private void drawMarker(Canvas canvas) {
|
||||
synchronized (markers) {
|
||||
for (Marker marker : markers) {
|
||||
double xValue = getMarkerXValue(marker);
|
||||
if (xValue > maxX) {
|
||||
continue;
|
||||
}
|
||||
canvas.save();
|
||||
float x = getX(getWaypointXValue(waypoint));
|
||||
float x = getX(getMarkerXValue(marker));
|
||||
canvas.drawLine(x, topBorder + spacer + markerHeight / 2, x, topBorder + effectiveHeight, markerPaint);
|
||||
canvas.translate(x - (markerWidth * WAYPOINT_X_ANCHOR), topBorder + spacer);
|
||||
canvas.translate(x - (markerWidth * MARKER_X_ANCHOR), topBorder + spacer);
|
||||
|
||||
waypointMarker.draw(canvas);
|
||||
markerPin.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
@@ -904,7 +900,7 @@ public class ChartView extends View {
|
||||
for (ChartValueSeries chartValueSeries : seriesList) {
|
||||
chartValueSeries.updateDimension();
|
||||
}
|
||||
float density = getContext().getResources().getDisplayMetrics().density;
|
||||
float density = getResources().getDisplayMetrics().density;
|
||||
spacer = (int) (density * SPACER);
|
||||
yAxisOffset = (int) (density * Y_AXIS_OFFSET);
|
||||
|
||||
@@ -975,17 +971,12 @@ public class ChartView extends View {
|
||||
return topBorder + yAxisOffset + (int) ((1 - percentage) * rangeHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a waypoint's x value.
|
||||
*
|
||||
* @param waypoint the waypoint
|
||||
*/
|
||||
private double getWaypointXValue(Waypoint waypoint) {
|
||||
private double getMarkerXValue(Marker marker) {
|
||||
if (chartByDistance) {
|
||||
double lenghtInKm = waypoint.getLength() * UnitConversions.M_TO_KM;
|
||||
return metricUnits ? lenghtInKm : lenghtInKm * UnitConversions.KM_TO_MI;
|
||||
double length_km = marker.getLength() * UnitConversions.M_TO_KM;
|
||||
return metricUnits ? length_km : length_km * UnitConversions.KM_TO_MI;
|
||||
} else {
|
||||
return waypoint.getDuration();
|
||||
return marker.getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import de.dennisguse.opentracks.util.StringUtils;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
|
||||
/**
|
||||
* Generates descriptions for tracks and waypoints.
|
||||
* Generates descriptions for tracks and markers.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
@@ -136,7 +136,9 @@ public class DescriptionGenerator {
|
||||
}
|
||||
|
||||
// Elevation gain
|
||||
writeElevation(stats.getTotalElevationGain(), builder, R.string.description_elevation_gain, lineBreak);
|
||||
if (stats.hasTotalElevationGain()) {
|
||||
writeElevation(stats.getTotalElevationGain(), builder, R.string.description_elevation_gain, lineBreak);
|
||||
}
|
||||
|
||||
// Recorded time
|
||||
builder.append(context.getString(R.string.description_recorded_time, StringUtils.formatDateTime(context, stats.getStartTime_ms())));
|
||||
|
||||
@@ -28,17 +28,17 @@ import java.util.Locale;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
|
||||
/**
|
||||
* Engine for searching for tracks and waypoints by text.
|
||||
* Engine for searching for tracks and markers by text.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
@@ -53,12 +53,12 @@ public class SearchEngine {
|
||||
TracksColumns.CATEGORY + " LIKE ?";
|
||||
|
||||
/**
|
||||
* WHERE query to get waypoints by name.
|
||||
* WHERE query to get markers by name.
|
||||
*/
|
||||
private static final String WAYPOINT_SELECTION_QUERY =
|
||||
WaypointsColumns.NAME + " LIKE ? OR " +
|
||||
WaypointsColumns.DESCRIPTION + " LIKE ? OR " +
|
||||
WaypointsColumns.CATEGORY + " LIKE ?";
|
||||
private static final String MARKER_SELECTION_QUERY =
|
||||
MarkerColumns.NAME + " LIKE ? OR " +
|
||||
MarkerColumns.DESCRIPTION + " LIKE ? OR " +
|
||||
MarkerColumns.CATEGORY + " LIKE ?";
|
||||
|
||||
/**
|
||||
* Order of track results.
|
||||
@@ -66,9 +66,9 @@ public class SearchEngine {
|
||||
private static final String TRACK_SELECTION_ORDER = TracksColumns._ID + " DESC LIMIT 1000";
|
||||
|
||||
/**
|
||||
* Order of waypoint results.
|
||||
* Order of marker results.
|
||||
*/
|
||||
private static final String WAYPOINT_SELECTION_ORDER = WaypointsColumns._ID + " DESC";
|
||||
private static final String MARKER_SELECTION_ORDER = MarkerColumns._ID + " DESC";
|
||||
|
||||
/**
|
||||
* How much we promote a match in the track category.
|
||||
@@ -86,9 +86,9 @@ public class SearchEngine {
|
||||
private static final double TRACK_NAME_PROMOTION = 16.0;
|
||||
|
||||
/**
|
||||
* How much we promote a waypoint result if it's in the currently-selected track.
|
||||
* How much we promote a marker result if it's in the currently-selected track.
|
||||
*/
|
||||
private static final double CURRENT_TRACK_WAYPOINT_PROMOTION = 2.0;
|
||||
private static final double CURRENT_TRACK_MARKER_PROMOTION = 2.0;
|
||||
|
||||
/**
|
||||
* How much we promote a track result if it's the currently-selected track.
|
||||
@@ -96,9 +96,9 @@ public class SearchEngine {
|
||||
private static final double CURRENT_TRACK_DEMOTION = 0.5;
|
||||
|
||||
/**
|
||||
* Maximum number of waypoints which will be retrieved and scored.
|
||||
* Maximum number of markers which will be retrieved and scored.
|
||||
*/
|
||||
private static final int MAX_SCORED_WAYPOINTS = 100;
|
||||
private static final int MAX_SCORED_MARKERS = 100;
|
||||
|
||||
/**
|
||||
* Oldest timestamp for which we rank based on time (2000-01-01 00:00:00.000)
|
||||
@@ -115,16 +115,16 @@ public class SearchEngine {
|
||||
return scoreDiff;
|
||||
}
|
||||
|
||||
// Make tracks come before waypoints.
|
||||
if (r1.waypoint != null && r2.track != null) {
|
||||
// Make tracks come before markers.
|
||||
if (r1.marker != null && r2.track != null) {
|
||||
return 1;
|
||||
} else if (r1.track != null && r2.waypoint != null) {
|
||||
} else if (r1.track != null && r2.marker != null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Finally, use arbitrary ordering, by ID.
|
||||
long id1 = r1.track != null ? r1.track.getId().getId() : r1.waypoint.getId().getId();
|
||||
long id2 = r2.track != null ? r2.track.getId().getId() : r2.waypoint.getId().getId();
|
||||
long id1 = r1.track != null ? r1.track.getId().getId() : r1.marker.getId().getId();
|
||||
long id2 = r2.track != null ? r2.track.getId().getId() : r2.marker.getId().getId();
|
||||
long idDiff = id2 - id1;
|
||||
return Long.signum(idDiff);
|
||||
};
|
||||
@@ -153,7 +153,7 @@ public class SearchEngine {
|
||||
TreeSet<ScoredResult> scoredResults = new TreeSet<>(SCORED_RESULT_COMPARATOR);
|
||||
|
||||
scoreTrackResults(retrieveTracks(query), query, scoredResults);
|
||||
scoreWaypointResults(retrieveWaypoints(query), query, scoredResults);
|
||||
scoreMarkersResults(retrieveMarkers(query), query, scoredResults);
|
||||
|
||||
return scoredResults;
|
||||
}
|
||||
@@ -186,33 +186,33 @@ public class SearchEngine {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves waypoints matching the given query from the database.
|
||||
* Retrieves markers matching the given query from the database.
|
||||
*
|
||||
* @param query the query to retrieve for
|
||||
*/
|
||||
private List<Waypoint> retrieveWaypoints(SearchQuery query) {
|
||||
ArrayList<Waypoint> waypoints = new ArrayList<>();
|
||||
private List<Marker> retrieveMarkers(SearchQuery query) {
|
||||
ArrayList<Marker> markers = new ArrayList<>();
|
||||
|
||||
String queryLikeSelection2 = "%" + query.textQuery + "%";
|
||||
String[] waypointSelectionArgs = new String[]{
|
||||
String[] markersSelectionArgs = new String[]{
|
||||
queryLikeSelection2,
|
||||
queryLikeSelection2,
|
||||
queryLikeSelection2
|
||||
};
|
||||
|
||||
try (Cursor cursor = providerUtils.getWaypointCursor(WAYPOINT_SELECTION_QUERY, waypointSelectionArgs, WAYPOINT_SELECTION_ORDER, MAX_SCORED_WAYPOINTS)) {
|
||||
try (Cursor cursor = providerUtils.getMarkerCursor(MARKER_SELECTION_QUERY, markersSelectionArgs, MARKER_SELECTION_ORDER, MAX_SCORED_MARKERS)) {
|
||||
if (cursor != null) {
|
||||
waypoints.ensureCapacity(cursor.getCount());
|
||||
markers.ensureCapacity(cursor.getCount());
|
||||
while (cursor.moveToNext()) {
|
||||
Waypoint waypoint = providerUtils.createWaypoint(cursor);
|
||||
if (LocationUtils.isValidLocation(waypoint.getLocation())) {
|
||||
waypoints.add(waypoint);
|
||||
Marker marker = providerUtils.createMarker(cursor);
|
||||
if (LocationUtils.isValidLocation(marker.getLocation())) {
|
||||
markers.add(marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return waypoints;
|
||||
return markers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,7 +250,7 @@ public class SearchEngine {
|
||||
score *= getTimeBoost(query, meanTimestamp);
|
||||
|
||||
// Score the currently-selected track lower (user is already there, wouldn't be searching for it).
|
||||
if (track.getId() == query.currentTrackId) {
|
||||
if (track.getId().equals(query.currentTrackId)) {
|
||||
score *= CURRENT_TRACK_DEMOTION;
|
||||
}
|
||||
|
||||
@@ -258,40 +258,40 @@ public class SearchEngine {
|
||||
}
|
||||
|
||||
/**
|
||||
* Scores a collection of waypoint results.
|
||||
* Scores a collection of marker results.
|
||||
*
|
||||
* @param waypoints the results to score
|
||||
* @param query the query to score for
|
||||
* @param output the collection to fill with scored results
|
||||
* @param markers the results to score
|
||||
* @param query the query to score for
|
||||
* @param output the collection to fill with scored results
|
||||
*/
|
||||
private void scoreWaypointResults(Collection<Waypoint> waypoints, SearchQuery query, Collection<ScoredResult> output) {
|
||||
for (Waypoint waypoint : waypoints) {
|
||||
private void scoreMarkersResults(Collection<Marker> markers, SearchQuery query, Collection<ScoredResult> output) {
|
||||
for (Marker marker : markers) {
|
||||
// Calculate the score.
|
||||
double score = scoreWaypointResult(query, waypoint);
|
||||
double score = scoreMarkerResult(query, marker);
|
||||
|
||||
// Add to the output.
|
||||
output.add(new ScoredResult(waypoint, score));
|
||||
output.add(new ScoredResult(marker, score));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scores a single waypoint result.
|
||||
* Scores a single marker result.
|
||||
*
|
||||
* @param query the query to score for
|
||||
* @param waypoint the results to score
|
||||
* @return the score for the waypoint
|
||||
* @param query the query to score for
|
||||
* @param marker the results to score
|
||||
* @return the score for the marker
|
||||
*/
|
||||
private double scoreWaypointResult(SearchQuery query, Waypoint waypoint) {
|
||||
private double scoreMarkerResult(SearchQuery query, Marker marker) {
|
||||
double score = 1.0;
|
||||
|
||||
Location location = waypoint.getLocation();
|
||||
score *= getTitleBoost(query, waypoint.getName(), waypoint.getDescription(), waypoint.getCategory());
|
||||
Location location = marker.getLocation();
|
||||
score *= getTitleBoost(query, marker.getName(), marker.getDescription(), marker.getCategory());
|
||||
score *= getDistanceBoost(query, location.getLatitude(), location.getLongitude());
|
||||
score *= getTimeBoost(query, location.getTime());
|
||||
|
||||
// Score waypoints in the currently-selected track higher (searching inside the current track).
|
||||
if (waypoint.getTrackId() != null && waypoint.getTrackId().equals(query.currentTrackId)) {
|
||||
score *= CURRENT_TRACK_WAYPOINT_PROMOTION;
|
||||
// Score markers in the currently-selected track higher (searching inside the current track).
|
||||
if (marker.getTrackId() != null && marker.getTrackId().equals(query.currentTrackId)) {
|
||||
score *= CURRENT_TRACK_MARKER_PROMOTION;
|
||||
}
|
||||
|
||||
return score;
|
||||
@@ -301,9 +301,9 @@ public class SearchEngine {
|
||||
* Calculates the boosting of the score due to the field(s) in which the match occured.
|
||||
*
|
||||
* @param query the query to boost for
|
||||
* @param name the name of the track or waypoint
|
||||
* @param description the description of the track or waypoint
|
||||
* @param category the category of the track or waypoint
|
||||
* @param name the name of the track or marker
|
||||
* @param description the description of the track or marker
|
||||
* @param category the category of the track or marker
|
||||
* @return the total boost to be applied to the result
|
||||
*/
|
||||
private double getTitleBoost(SearchQuery query, String name, String description, String category) {
|
||||
@@ -398,18 +398,18 @@ public class SearchEngine {
|
||||
*/
|
||||
public static class ScoredResult {
|
||||
public final Track track;
|
||||
public final Waypoint waypoint;
|
||||
public final Marker marker;
|
||||
final double score;
|
||||
|
||||
ScoredResult(Track track, double score) {
|
||||
this.track = track;
|
||||
this.waypoint = null;
|
||||
this.marker = null;
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
ScoredResult(Waypoint waypoint, double score) {
|
||||
ScoredResult(Marker marker, double score) {
|
||||
this.track = null;
|
||||
this.waypoint = waypoint;
|
||||
this.marker = marker;
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ public class SearchEngine {
|
||||
public String toString() {
|
||||
return "ScoredResult ["
|
||||
+ (track != null ? ("trackId=" + track.getId().getId() + ", ") : "")
|
||||
+ (waypoint != null ? ("wptId=" + waypoint.getId().getId() + ", ") : "")
|
||||
+ (marker != null ? ("wptId=" + marker.getId().getId() + ", ") : "")
|
||||
+ "score=" + score + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
@@ -58,14 +58,14 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
* We may display more than this number of points.
|
||||
*/
|
||||
@Deprecated
|
||||
private static final int TARGET_DISPLAYED_TRACK_POINTS = 5000;
|
||||
private static final int TARGET_DISPLAYED_TRACKPOINTS = 5000;
|
||||
|
||||
/**
|
||||
* Maximum number of waypoints to displayed.
|
||||
* Maximum number of markers to displayed.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Deprecated
|
||||
private static final int MAX_DISPLAYED_WAYPOINTS = 128;
|
||||
private static final int MAX_DISPLAYED_MARKERS = 128;
|
||||
|
||||
private static final String TAG = TrackDataHub.class.getSimpleName();
|
||||
|
||||
@@ -90,11 +90,11 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
|
||||
// Registered listeners
|
||||
private ContentObserver tracksTableObserver;
|
||||
private ContentObserver waypointsTableObserver;
|
||||
private ContentObserver markersTableObserver;
|
||||
private ContentObserver trackPointsTableObserver;
|
||||
|
||||
public TrackDataHub(Context context) {
|
||||
this(context, new TrackDataManager(), new ContentProviderUtils(context), TARGET_DISPLAYED_TRACK_POINTS);
|
||||
this(context, new TrackDataManager(), new ContentProviderUtils(context), TARGET_DISPLAYED_TRACKPOINTS);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -126,13 +126,13 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
};
|
||||
contentResolver.registerContentObserver(TracksColumns.CONTENT_URI, false, tracksTableObserver);
|
||||
|
||||
waypointsTableObserver = new ContentObserver(handler) {
|
||||
markersTableObserver = new ContentObserver(handler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
notifyWaypointsTableUpdate(trackDataManager.getListenerWaypoints());
|
||||
notifyMarkersTableUpdate(trackDataManager.getListenerMarkers());
|
||||
}
|
||||
};
|
||||
contentResolver.registerContentObserver(WaypointsColumns.CONTENT_URI, false, waypointsTableObserver);
|
||||
contentResolver.registerContentObserver(MarkerColumns.CONTENT_URI, false, markersTableObserver);
|
||||
|
||||
trackPointsTableObserver = new ContentObserver(handler) {
|
||||
@Override
|
||||
@@ -165,7 +165,7 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
//Unregister listeners
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
contentResolver.unregisterContentObserver(tracksTableObserver);
|
||||
contentResolver.unregisterContentObserver(waypointsTableObserver);
|
||||
contentResolver.unregisterContentObserver(markersTableObserver);
|
||||
contentResolver.unregisterContentObserver(trackPointsTableObserver);
|
||||
|
||||
if (handlerThread != null) {
|
||||
@@ -191,9 +191,9 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
*
|
||||
* @param trackDataListener the track data listener
|
||||
*/
|
||||
public void registerTrackDataListener(final TrackDataListener trackDataListener, final boolean tracksTable, final boolean waypointsTable, final boolean trackPointsTable_SampleIn, final boolean trackPointsTable_SampleOut) {
|
||||
public void registerTrackDataListener(final TrackDataListener trackDataListener, final boolean tracksTable, final boolean markersTable, final boolean trackPointsTable_SampleIn, final boolean trackPointsTable_SampleOut) {
|
||||
runInHandlerThread(() -> {
|
||||
trackDataManager.registerTrackDataListener(trackDataListener, tracksTable, waypointsTable, trackPointsTable_SampleIn, trackPointsTable_SampleOut);
|
||||
trackDataManager.registerTrackDataListener(trackDataListener, tracksTable, markersTable, trackPointsTable_SampleIn, trackPointsTable_SampleOut);
|
||||
if (started) {
|
||||
loadDataForListener(trackDataListener);
|
||||
}
|
||||
@@ -250,7 +250,7 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
listener.clearTrackPoints();
|
||||
}
|
||||
notifyTrackPointsTableUpdate(true, trackDataManager.getListenerTrackPoints_SampledIn(), trackDataManager.getListenerTrackPoints_SampledOut());
|
||||
notifyWaypointsTableUpdate(trackDataManager.getListenerWaypoints());
|
||||
notifyMarkersTableUpdate(trackDataManager.getListenerMarkers());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,8 +277,8 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
notifyTrackPointsTableUpdate(isOnlyListener, trackDataListeners, sampledOutListeners);
|
||||
}
|
||||
|
||||
if (trackDataManager.listensForWaypoints(trackDataListener)) {
|
||||
notifyWaypointsTableUpdate(trackDataListeners);
|
||||
if (trackDataManager.listensForMarkers(trackDataListener)) {
|
||||
notifyMarkersTableUpdate(trackDataListeners);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,36 +298,36 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies waypoint table update.
|
||||
* Currently, reloads all the waypoints up to {@link #MAX_DISPLAYED_WAYPOINTS}. To be run in the {@link #handler} thread.
|
||||
* Notifies marker table update.
|
||||
* Currently, reloads all the markers up to {@link #MAX_DISPLAYED_MARKERS}. To be run in the {@link #handler} thread.
|
||||
*
|
||||
* @param trackDataListeners the track data listeners to notify
|
||||
*/
|
||||
private void notifyWaypointsTableUpdate(Set<TrackDataListener> trackDataListeners) {
|
||||
private void notifyMarkersTableUpdate(Set<TrackDataListener> trackDataListeners) {
|
||||
if (trackDataListeners.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (TrackDataListener trackDataListener : trackDataListeners) {
|
||||
trackDataListener.clearWaypoints();
|
||||
trackDataListener.clearMarkers();
|
||||
}
|
||||
|
||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(selectedTrackId, null, MAX_DISPLAYED_WAYPOINTS)) {
|
||||
try (Cursor cursor = contentProviderUtils.getMarkerCursor(selectedTrackId, null, MAX_DISPLAYED_MARKERS)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursor);
|
||||
if (!LocationUtils.isValidLocation(waypoint.getLocation())) {
|
||||
Marker marker = contentProviderUtils.createMarker(cursor);
|
||||
if (!LocationUtils.isValidLocation(marker.getLocation())) {
|
||||
continue;
|
||||
}
|
||||
for (TrackDataListener trackDataListener : trackDataListeners) {
|
||||
trackDataListener.onNewWaypoint(waypoint);
|
||||
trackDataListener.onNewMarker(marker);
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
}
|
||||
|
||||
for (TrackDataListener trackDataListener : trackDataListeners) {
|
||||
trackDataListener.onNewWaypointsDone();
|
||||
trackDataListener.onNewMarkersDone();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package de.dennisguse.opentracks.content;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
|
||||
/**
|
||||
* Listener for track data changes.
|
||||
@@ -60,20 +60,20 @@ public interface TrackDataListener {
|
||||
void onNewTrackPointsDone();
|
||||
|
||||
/**
|
||||
* Called to clear previously sent waypoints.
|
||||
* Called to clear previously sent markers.
|
||||
*/
|
||||
void clearWaypoints();
|
||||
void clearMarkers();
|
||||
|
||||
/**
|
||||
* Called when a new waypoint is read.
|
||||
* Called when a new marker is read.
|
||||
*
|
||||
* @param waypoint the waypoint
|
||||
* @param marker the marker
|
||||
*/
|
||||
void onNewWaypoint(Waypoint waypoint);
|
||||
void onNewMarker(Marker marker);
|
||||
|
||||
/**
|
||||
* Called when finish sending new waypoints.
|
||||
* This gets called after every batch of calls to {@link #clearWaypoints()} and {@link #onNewWaypoint(Waypoint)}.
|
||||
* Called when finish sending new markers.
|
||||
* This gets called after every batch of calls to {@link #clearMarkers()} and {@link #onNewMarker(Marker)}.
|
||||
*/
|
||||
void onNewWaypointsDone();
|
||||
void onNewMarkersDone();
|
||||
}
|
||||
|
||||
@@ -29,32 +29,32 @@ class TrackDataManager {
|
||||
private static final String TAG = TrackDataManager.class.getSimpleName();
|
||||
|
||||
private final Set<TrackDataListener> dataListenerTracks = new HashSet<>();
|
||||
private final Set<TrackDataListener> dataListenerWaypoints = new HashSet<>();
|
||||
private final Set<TrackDataListener> dataListenerMarkers = new HashSet<>();
|
||||
private final Set<TrackDataListener> dataListenerTrackPoints_SampledIn = new HashSet<>();
|
||||
private final Set<TrackDataListener> dataListenerTrackPoints_SampledOut = new HashSet<>();
|
||||
|
||||
void registerTrackDataListener(final TrackDataListener trackDataListener, boolean tracksTable, boolean waypointsTable, boolean trackPointsTable_SampleIn, boolean trackPointsTable_SampleOut) {
|
||||
void registerTrackDataListener(final TrackDataListener trackDataListener, boolean tracksTable, boolean markersTable, boolean trackPointsTable_SampleIn, boolean trackPointsTable_SampleOut) {
|
||||
if (tracksTable) dataListenerTracks.add(trackDataListener);
|
||||
if (waypointsTable) dataListenerWaypoints.add(trackDataListener);
|
||||
if (markersTable) dataListenerMarkers.add(trackDataListener);
|
||||
if (trackPointsTable_SampleIn) dataListenerTrackPoints_SampledIn.add(trackDataListener);
|
||||
if (trackPointsTable_SampleOut) dataListenerTrackPoints_SampledOut.add(trackDataListener);
|
||||
}
|
||||
|
||||
void unregisterTrackDataListener(TrackDataListener trackDataListener) {
|
||||
dataListenerTracks.add(trackDataListener);
|
||||
dataListenerWaypoints.add(trackDataListener);
|
||||
dataListenerMarkers.add(trackDataListener);
|
||||
dataListenerTrackPoints_SampledIn.add(trackDataListener);
|
||||
dataListenerTrackPoints_SampledOut.add(trackDataListener);
|
||||
}
|
||||
|
||||
boolean hasListeners() {
|
||||
return dataListenerTracks.size() + dataListenerWaypoints.size() + dataListenerTrackPoints_SampledIn.size() + dataListenerTrackPoints_SampledOut.size() > 0;
|
||||
return dataListenerTracks.size() + dataListenerMarkers.size() + dataListenerTrackPoints_SampledIn.size() + dataListenerTrackPoints_SampledOut.size() > 0;
|
||||
}
|
||||
|
||||
int getNumberOfListeners() {
|
||||
Set<TrackDataListener> listener = new HashSet<>();
|
||||
listener.addAll(dataListenerTracks);
|
||||
listener.addAll(dataListenerWaypoints);
|
||||
listener.addAll(dataListenerMarkers);
|
||||
listener.addAll(dataListenerTrackPoints_SampledIn);
|
||||
listener.addAll(dataListenerTrackPoints_SampledOut);
|
||||
|
||||
@@ -65,8 +65,8 @@ class TrackDataManager {
|
||||
return dataListenerTracks.contains(listener);
|
||||
}
|
||||
|
||||
boolean listensForWaypoints(TrackDataListener listener) {
|
||||
return dataListenerWaypoints.contains(listener);
|
||||
boolean listensForMarkers(TrackDataListener listener) {
|
||||
return dataListenerMarkers.contains(listener);
|
||||
}
|
||||
|
||||
boolean listensForTrackPoints_SampledIn(TrackDataListener listener) {
|
||||
@@ -81,8 +81,8 @@ class TrackDataManager {
|
||||
return dataListenerTracks;
|
||||
}
|
||||
|
||||
Set<TrackDataListener> getListenerWaypoints() {
|
||||
return dataListenerWaypoints;
|
||||
Set<TrackDataListener> getListenerMarkers() {
|
||||
return dataListenerMarkers;
|
||||
}
|
||||
|
||||
Set<TrackDataListener> getListenerTrackPoints_SampledIn() {
|
||||
|
||||
+6
-12
@@ -30,12 +30,10 @@ import java.util.Objects;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
/**
|
||||
* A waypoint.
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public final class Waypoint {
|
||||
public final class Marker {
|
||||
|
||||
private Id id;
|
||||
private String name = "";
|
||||
@@ -50,15 +48,15 @@ public final class Waypoint {
|
||||
private String photoUrl = "";
|
||||
|
||||
@VisibleForTesting
|
||||
public Waypoint(@NonNull TrackPoint trackPoint) {
|
||||
public Marker(@NonNull TrackPoint trackPoint) {
|
||||
this.location = trackPoint.getLocation();
|
||||
}
|
||||
|
||||
public Waypoint(@NonNull Location location) {
|
||||
public Marker(@NonNull Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public Waypoint(String name, String description, String category, String icon, @NonNull Track.Id trackId, double length, long duration, @NonNull Location location, String photoUrl) {
|
||||
public Marker(String name, String description, String category, String icon, @NonNull Track.Id trackId, double length, long duration, @NonNull Location location, String photoUrl) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.category = category;
|
||||
@@ -71,7 +69,7 @@ public final class Waypoint {
|
||||
}
|
||||
|
||||
/**
|
||||
* May be null if the waypoint was not loaded from the database.
|
||||
* May be null if the it was not loaded from the database.
|
||||
*/
|
||||
public @Nullable
|
||||
Id getId() {
|
||||
@@ -167,16 +165,12 @@ public final class Waypoint {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Id(@NonNull String id) {
|
||||
this(Long.parseLong(id));
|
||||
}
|
||||
|
||||
//TOOD Limit visibility to TrackRecordingService / ContentProvider
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Deprecated //TODO Use a Waypoint.Id of null instead
|
||||
@Deprecated //TODO Use a Id of null instead
|
||||
public boolean isValid() {
|
||||
return id != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||
}
|
||||
+6
-6
@@ -22,11 +22,11 @@ import android.provider.BaseColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
|
||||
/**
|
||||
* Constants for waypoints table.
|
||||
* Constants for markers table.
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
*/
|
||||
public interface WaypointsColumns extends BaseColumns {
|
||||
public interface MarkerColumns extends BaseColumns {
|
||||
|
||||
String TABLE_NAME = "waypoints";
|
||||
Uri CONTENT_URI = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/" + TABLE_NAME);
|
||||
@@ -36,10 +36,10 @@ public interface WaypointsColumns extends BaseColumns {
|
||||
String DEFAULT_SORT_ORDER = _ID;
|
||||
|
||||
// Columns
|
||||
String NAME = "name"; // waypoint name
|
||||
String DESCRIPTION = "description"; // waypoint description
|
||||
String CATEGORY = "category"; // waypoint category
|
||||
String ICON = "icon"; // waypoint icon
|
||||
String NAME = "name"; // marker name
|
||||
String DESCRIPTION = "description"; // marker description
|
||||
String CATEGORY = "category"; // marker category
|
||||
String ICON = "icon"; // marker icon
|
||||
String TRACKID = "trackid"; // track id
|
||||
|
||||
String LENGTH = "length"; // length of the track (without smoothing)
|
||||
@@ -118,10 +118,6 @@ public class Track {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Id(@NonNull String id) {
|
||||
this(Long.parseLong(id));
|
||||
}
|
||||
|
||||
//TOOD Limit visibility to TrackRecordingService / ContentProvider
|
||||
public long getId() {
|
||||
return id;
|
||||
|
||||
@@ -32,6 +32,7 @@ public class TrackPoint {
|
||||
private Float heartRate_bpm = null;
|
||||
private Float cyclingCadence_rpm = null;
|
||||
private Float power = null;
|
||||
private Float elevationGain = null;
|
||||
|
||||
public TrackPoint() {
|
||||
this.location = new Location("");
|
||||
@@ -47,6 +48,8 @@ public class TrackPoint {
|
||||
this.heartRate_bpm = trackPoint.getHeartRate_bpm();
|
||||
this.cyclingCadence_rpm = trackPoint.getCyclingCadence_rpm();
|
||||
this.power = trackPoint.getPower();
|
||||
|
||||
this.elevationGain = trackPoint.getElevationGain();
|
||||
}
|
||||
|
||||
public TrackPoint(double latitude, double longitude, Double altitude, long time) {
|
||||
@@ -59,10 +62,12 @@ public class TrackPoint {
|
||||
location.setTime(time);
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createPause() {
|
||||
return createPauseWithTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createPauseWithTime(long time) {
|
||||
Location pause = new Location(LocationManager.GPS_PROVIDER);
|
||||
pause.setLongitude(0);
|
||||
@@ -71,10 +76,12 @@ public class TrackPoint {
|
||||
return new TrackPoint(pause);
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createResume() {
|
||||
return createResumeWithTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createResumeWithTime(long time) {
|
||||
Location resume = new Location(LocationManager.GPS_PROVIDER);
|
||||
resume.setLongitude(0);
|
||||
@@ -88,6 +95,18 @@ public class TrackPoint {
|
||||
return location;
|
||||
}
|
||||
|
||||
public boolean hasElevationGain() {
|
||||
return elevationGain != null;
|
||||
}
|
||||
|
||||
public float getElevationGain() {
|
||||
return elevationGain;
|
||||
}
|
||||
|
||||
public void setElevationGain(Float elevationGain) {
|
||||
this.elevationGain = elevationGain;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return location.getLatitude();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ public interface TrackPointsColumns extends BaseColumns {
|
||||
String SENSOR_HEARTRATE = "sensor_heartrate";
|
||||
String SENSOR_CADENCE = "sensor_cadence";
|
||||
String SENSOR_POWER = "sensor_power";
|
||||
String ELEVATION_GAIN = "elevation_gain";
|
||||
|
||||
String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " ("
|
||||
+ _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
@@ -64,7 +65,8 @@ public interface TrackPointsColumns extends BaseColumns {
|
||||
+ BEARING + " FLOAT, "
|
||||
+ SENSOR_HEARTRATE + " FLOAT, "
|
||||
+ SENSOR_CADENCE + " FLOAT, "
|
||||
+ SENSOR_POWER + " FLOAT)";
|
||||
+ SENSOR_POWER + " FLOAT, "
|
||||
+ ELEVATION_GAIN + " FLOAT)";
|
||||
|
||||
String CREATE_TABLE_INDEX = "CREATE INDEX " + TABLE_NAME + "_" + TRACKID + "_index ON " + TABLE_NAME + "(" + TRACKID + ")";
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ class CachedTrackPointsIndexes {
|
||||
final int sensorHeartRateIndex;
|
||||
final int sensorCadenceIndex;
|
||||
final int sensorPowerIndex;
|
||||
final int elevationGainIndex;
|
||||
|
||||
CachedTrackPointsIndexes(Cursor cursor) {
|
||||
idIndex = cursor.getColumnIndex(TrackPointsColumns._ID);
|
||||
@@ -32,5 +33,6 @@ class CachedTrackPointsIndexes {
|
||||
sensorHeartRateIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE);
|
||||
sensorCadenceIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_CADENCE);
|
||||
sensorPowerIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_POWER);
|
||||
elevationGainIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ELEVATION_GAIN);
|
||||
}
|
||||
}
|
||||
|
||||
+132
-155
@@ -40,12 +40,12 @@ import java.util.UUID;
|
||||
import de.dennisguse.opentracks.BuildConfig;
|
||||
import de.dennisguse.opentracks.android.ContentResolverWrapper;
|
||||
import de.dennisguse.opentracks.android.IContentResolver;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
import de.dennisguse.opentracks.util.TrackUtils;
|
||||
@@ -69,8 +69,8 @@ public class ContentProviderUtils {
|
||||
// The base URI for the app's content provider.
|
||||
public static final String CONTENT_BASE_URI = "content://" + AUTHORITY_PACKAGE;
|
||||
|
||||
// Maximum number of waypoints that will be loaded at one time.
|
||||
public static final int MAX_LOADED_WAYPOINTS_POINTS = 10000;
|
||||
// Maximum number of markers that will be loaded at one time.
|
||||
public static final int MAX_LOADED_MARKERS = 10000;
|
||||
private static final String ID_SEPARATOR = ",";
|
||||
|
||||
private final IContentResolver contentResolver;
|
||||
@@ -89,13 +89,13 @@ public class ContentProviderUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a track: removes waypoints and trackPoints.
|
||||
* Clears a track: removes markers and trackPoints.
|
||||
* Only keeps the track id.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
public void clearTrack(Track.Id trackId) {
|
||||
deleteTrackPointsAndWaypoints(trackId);
|
||||
deleteTrackPointsAndMarkers(trackId);
|
||||
Track track = new Track();
|
||||
track.setId(trackId);
|
||||
updateTrack(track);
|
||||
@@ -176,7 +176,7 @@ public class ContentProviderUtils {
|
||||
@VisibleForTesting
|
||||
public void deleteAllTracks(Context context) {
|
||||
contentResolver.delete(TrackPointsColumns.CONTENT_URI_BY_ID, null, null);
|
||||
contentResolver.delete(WaypointsColumns.CONTENT_URI, null, null);
|
||||
contentResolver.delete(MarkerColumns.CONTENT_URI, null, null);
|
||||
// Delete tracks last since it triggers a database vaccum call
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, null, null);
|
||||
|
||||
@@ -193,7 +193,7 @@ public class ContentProviderUtils {
|
||||
if (trackId == null) {
|
||||
return;
|
||||
}
|
||||
deleteTrackPointsAndWaypoints(trackId);
|
||||
deleteTrackPointsAndMarkers(trackId);
|
||||
|
||||
// Delete track folder resources.
|
||||
FileUtils.deleteDirectoryRecurse(FileUtils.getPhotoDir(context, trackId));
|
||||
@@ -202,16 +202,11 @@ public class ContentProviderUtils {
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, TracksColumns._ID + "=?", new String[]{Long.toString(trackId.getId())});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes trackPoints and waypoints of a track.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
private void deleteTrackPointsAndWaypoints(@NonNull Track.Id trackId) {
|
||||
private void deleteTrackPointsAndMarkers(@NonNull Track.Id trackId) {
|
||||
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||
|
||||
contentResolver.delete(TrackPointsColumns.CONTENT_URI_BY_ID, TrackPointsColumns.TRACKID + "=?", selectionArgs);
|
||||
contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns.TRACKID + "=?", selectionArgs);
|
||||
contentResolver.delete(MarkerColumns.CONTENT_URI, MarkerColumns.TRACKID + "=?", selectionArgs);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -338,28 +333,22 @@ public class ContentProviderUtils {
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a waypoint from a cursor.
|
||||
*
|
||||
* @param cursor the cursor pointing to the waypoint
|
||||
*/
|
||||
public Waypoint createWaypoint(Cursor cursor) {
|
||||
int idIndex = cursor.getColumnIndexOrThrow(WaypointsColumns._ID);
|
||||
int nameIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.NAME);
|
||||
int descriptionIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.DESCRIPTION);
|
||||
int categoryIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.CATEGORY);
|
||||
int iconIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ICON);
|
||||
int trackIdIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.TRACKID);
|
||||
int lengthIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.LENGTH);
|
||||
int durationIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.DURATION);
|
||||
int longitudeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.LONGITUDE);
|
||||
int latitudeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.LATITUDE);
|
||||
int timeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.TIME);
|
||||
int altitudeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ALTITUDE);
|
||||
int accuracyIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ACCURACY);
|
||||
int bearingIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.BEARING);
|
||||
int photoUrlIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.PHOTOURL);
|
||||
public Marker createMarker(Cursor cursor) {
|
||||
int idIndex = cursor.getColumnIndexOrThrow(MarkerColumns._ID);
|
||||
int nameIndex = cursor.getColumnIndexOrThrow(MarkerColumns.NAME);
|
||||
int descriptionIndex = cursor.getColumnIndexOrThrow(MarkerColumns.DESCRIPTION);
|
||||
int categoryIndex = cursor.getColumnIndexOrThrow(MarkerColumns.CATEGORY);
|
||||
int iconIndex = cursor.getColumnIndexOrThrow(MarkerColumns.ICON);
|
||||
int trackIdIndex = cursor.getColumnIndexOrThrow(MarkerColumns.TRACKID);
|
||||
int lengthIndex = cursor.getColumnIndexOrThrow(MarkerColumns.LENGTH);
|
||||
int durationIndex = cursor.getColumnIndexOrThrow(MarkerColumns.DURATION);
|
||||
int longitudeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.LONGITUDE);
|
||||
int latitudeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.LATITUDE);
|
||||
int timeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.TIME);
|
||||
int altitudeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.ALTITUDE);
|
||||
int accuracyIndex = cursor.getColumnIndexOrThrow(MarkerColumns.ACCURACY);
|
||||
int bearingIndex = cursor.getColumnIndexOrThrow(MarkerColumns.BEARING);
|
||||
int photoUrlIndex = cursor.getColumnIndexOrThrow(MarkerColumns.PHOTOURL);
|
||||
|
||||
Location location = new Location("");
|
||||
if (!cursor.isNull(longitudeIndex) && !cursor.isNull(latitudeIndex)) {
|
||||
@@ -379,59 +368,56 @@ public class ContentProviderUtils {
|
||||
location.setBearing(cursor.getFloat(bearingIndex));
|
||||
}
|
||||
|
||||
Waypoint waypoint = new Waypoint(location);
|
||||
Marker marker = new Marker(location);
|
||||
|
||||
if (!cursor.isNull(idIndex)) {
|
||||
waypoint.setId(new Waypoint.Id(cursor.getLong(idIndex)));
|
||||
marker.setId(new Marker.Id(cursor.getLong(idIndex)));
|
||||
}
|
||||
if (!cursor.isNull(nameIndex)) {
|
||||
waypoint.setName(cursor.getString(nameIndex));
|
||||
marker.setName(cursor.getString(nameIndex));
|
||||
}
|
||||
if (!cursor.isNull(descriptionIndex)) {
|
||||
waypoint.setDescription(cursor.getString(descriptionIndex));
|
||||
marker.setDescription(cursor.getString(descriptionIndex));
|
||||
}
|
||||
if (!cursor.isNull(categoryIndex)) {
|
||||
waypoint.setCategory(cursor.getString(categoryIndex));
|
||||
marker.setCategory(cursor.getString(categoryIndex));
|
||||
}
|
||||
if (!cursor.isNull(iconIndex)) {
|
||||
waypoint.setIcon(cursor.getString(iconIndex));
|
||||
marker.setIcon(cursor.getString(iconIndex));
|
||||
}
|
||||
if (!cursor.isNull(trackIdIndex)) {
|
||||
waypoint.setTrackId(new Track.Id(cursor.getLong(trackIdIndex)));
|
||||
marker.setTrackId(new Track.Id(cursor.getLong(trackIdIndex)));
|
||||
}
|
||||
if (!cursor.isNull(lengthIndex)) {
|
||||
waypoint.setLength(cursor.getFloat(lengthIndex));
|
||||
marker.setLength(cursor.getFloat(lengthIndex));
|
||||
}
|
||||
if (!cursor.isNull(durationIndex)) {
|
||||
waypoint.setDuration(cursor.getLong(durationIndex));
|
||||
marker.setDuration(cursor.getLong(durationIndex));
|
||||
}
|
||||
|
||||
if (!cursor.isNull(photoUrlIndex)) {
|
||||
waypoint.setPhotoUrl(cursor.getString(photoUrlIndex));
|
||||
marker.setPhotoUrl(cursor.getString(photoUrlIndex));
|
||||
}
|
||||
return waypoint;
|
||||
return marker;
|
||||
}
|
||||
|
||||
public void deleteWaypoint(Context context, Waypoint.Id waypointId) {
|
||||
final Waypoint waypoint = getWaypoint(waypointId);
|
||||
deleteWaypointPhoto(context, waypoint);
|
||||
contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns._ID + "=?", new String[]{Long.toString(waypointId.getId())});
|
||||
public void deleteMarker(Context context, Marker.Id markerId) {
|
||||
final Marker marker = getMarker(markerId);
|
||||
deleteMarkerPhoto(context, marker);
|
||||
contentResolver.delete(MarkerColumns.CONTENT_URI, MarkerColumns._ID + "=?", new String[]{Long.toString(markerId.getId())});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next waypoint number.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @return -1 if not able to get the next waypoint number.
|
||||
* @return -1 if not able to get the next marker number.
|
||||
*/
|
||||
public int getNextWaypointNumber(Track.Id trackId) {
|
||||
public int getNextMarkerNumber(Track.Id trackId) {
|
||||
if (!trackId.isValid()) {
|
||||
return -1;
|
||||
}
|
||||
String[] projection = {WaypointsColumns._ID};
|
||||
String selection = WaypointsColumns.TRACKID + "=?";
|
||||
String[] projection = {MarkerColumns._ID};
|
||||
String selection = MarkerColumns.TRACKID + "=?";
|
||||
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||
try (Cursor cursor = getWaypointCursor(projection, selection, selectionArgs, WaypointsColumns._ID, -1)) {
|
||||
try (Cursor cursor = getMarkerCursor(projection, selection, selectionArgs, MarkerColumns._ID, -1)) {
|
||||
if (cursor != null) {
|
||||
return cursor.getCount();
|
||||
}
|
||||
@@ -439,99 +425,94 @@ public class ContentProviderUtils {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Waypoint getWaypoint(Waypoint.Id waypointId) {
|
||||
if (!waypointId.isValid()) {
|
||||
public Marker getMarker(Marker.Id markerId) {
|
||||
if (!markerId.isValid()) {
|
||||
return null;
|
||||
}
|
||||
try (Cursor cursor = getWaypointCursor(null, WaypointsColumns._ID + "=?",
|
||||
new String[]{Long.toString(waypointId.getId())}, WaypointsColumns._ID, 1)) {
|
||||
try (Cursor cursor = getMarkerCursor(null, MarkerColumns._ID + "=?",
|
||||
new String[]{Long.toString(markerId.getId())}, MarkerColumns._ID, 1)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return createWaypoint(cursor);
|
||||
return createMarker(cursor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a waypoint cursor.
|
||||
* he caller owns the returned cursor and is responsible for closing it.
|
||||
* The caller owns the returned cursor and is responsible for closing it.
|
||||
*
|
||||
* @param selection the selection. Can be null
|
||||
* @param selectionArgs the selection arguments. Can be null
|
||||
* @param sortOrder the sort order. Can be null
|
||||
* @param maxWaypoints the maximum number of waypoints to return. -1 for no limit
|
||||
* @param maxCount the maximum number of markers to return. -1 for no limit
|
||||
*/
|
||||
public Cursor getWaypointCursor(String selection, String[] selectionArgs, String sortOrder, int maxWaypoints) {
|
||||
return getWaypointCursor(null, selection, selectionArgs, sortOrder, maxWaypoints);
|
||||
public Cursor getMarkerCursor(String selection, String[] selectionArgs, String sortOrder, int maxCount) {
|
||||
return getMarkerCursor(null, selection, selectionArgs, sortOrder, maxCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a waypoint cursor for a track.
|
||||
* The caller owns the returned cursor and is responsible for closing it.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @param minWaypointId the minimum waypoint id. null to ignore
|
||||
* @param maxWaypoints the maximum number of waypoints to return. -1 for no limit
|
||||
* @param trackId the track id
|
||||
* @param minMarkerId the minimum marker id. null to ignore
|
||||
* @param maxCount the maximum number of markers to return. -1 for no limit
|
||||
*/
|
||||
public Cursor getWaypointCursor(Track.Id trackId, @Nullable Waypoint.Id minWaypointId, int maxWaypoints) {
|
||||
public Cursor getMarkerCursor(Track.Id trackId, @Nullable Marker.Id minMarkerId, int maxCount) {
|
||||
if (!trackId.isValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String selection;
|
||||
String[] selectionArgs;
|
||||
if (minWaypointId != null && minWaypointId.isValid()) {
|
||||
selection = WaypointsColumns.TRACKID + "=? AND " + WaypointsColumns._ID + ">=?";
|
||||
selectionArgs = new String[]{Long.toString(trackId.getId()), Long.toString(minWaypointId.getId())};
|
||||
if (minMarkerId != null && minMarkerId.isValid()) {
|
||||
selection = MarkerColumns.TRACKID + "=? AND " + MarkerColumns._ID + ">=?";
|
||||
selectionArgs = new String[]{Long.toString(trackId.getId()), Long.toString(minMarkerId.getId())};
|
||||
} else {
|
||||
selection = WaypointsColumns.TRACKID + "=?";
|
||||
selection = MarkerColumns.TRACKID + "=?";
|
||||
selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||
}
|
||||
return getWaypointCursor(null, selection, selectionArgs, WaypointsColumns._ID, maxWaypoints);
|
||||
return getMarkerCursor(null, selection, selectionArgs, MarkerColumns._ID, maxCount);
|
||||
}
|
||||
|
||||
@Deprecated //TODO Move to test package
|
||||
@VisibleForTesting
|
||||
public List<Waypoint> getWaypoints(Track.Id trackId) {
|
||||
ArrayList<Waypoint> waypoints = new ArrayList<>();
|
||||
try (Cursor cursor = getWaypointCursor(trackId, null, -1)) {
|
||||
public List<Marker> getMarkers(Track.Id trackId) {
|
||||
ArrayList<Marker> markers = new ArrayList<>();
|
||||
try (Cursor cursor = getMarkerCursor(trackId, null, -1)) {
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
waypoints.add(createWaypoint(cursor));
|
||||
markers.add(createMarker(cursor));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
}
|
||||
return waypoints;
|
||||
return markers;
|
||||
}
|
||||
|
||||
public static Loader<Cursor> getWaypointsLoader(Context context, @Nullable Track.Id trackId) {
|
||||
final String[] PROJECTION = new String[]{WaypointsColumns._ID,
|
||||
WaypointsColumns.NAME, WaypointsColumns.DESCRIPTION, WaypointsColumns.CATEGORY,
|
||||
WaypointsColumns.TIME, WaypointsColumns.PHOTOURL,
|
||||
WaypointsColumns.LATITUDE, WaypointsColumns.LONGITUDE};
|
||||
public static Loader<Cursor> getMarkersLoader(Context context, @Nullable Track.Id trackId) {
|
||||
final String[] PROJECTION = new String[]{MarkerColumns._ID,
|
||||
MarkerColumns.NAME, MarkerColumns.DESCRIPTION, MarkerColumns.CATEGORY,
|
||||
MarkerColumns.TIME, MarkerColumns.PHOTOURL,
|
||||
MarkerColumns.LATITUDE, MarkerColumns.LONGITUDE};
|
||||
|
||||
if (trackId != null) {
|
||||
return new CursorLoader(context, WaypointsColumns.CONTENT_URI, PROJECTION,
|
||||
WaypointsColumns.TRACKID + "=?",
|
||||
return new CursorLoader(context, MarkerColumns.CONTENT_URI, PROJECTION,
|
||||
MarkerColumns.TRACKID + "=?",
|
||||
new String[]{String.valueOf(trackId.getId())}, null);
|
||||
} else {
|
||||
return new CursorLoader(context, WaypointsColumns.CONTENT_URI, PROJECTION, null, null, null);
|
||||
return new CursorLoader(context, MarkerColumns.CONTENT_URI, PROJECTION, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of waypoints for a track.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
public int getWaypointCount(Track.Id trackId) {
|
||||
@Deprecated //TODO Expose information via Cursor
|
||||
public int getMarkerCount(Track.Id trackId) {
|
||||
if (!trackId.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
String[] projection = new String[]{"count(*) AS count"};
|
||||
String selection = WaypointsColumns.TRACKID + "=?";
|
||||
String selection = MarkerColumns.TRACKID + "=?";
|
||||
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||
try (Cursor cursor = contentResolver.query(WaypointsColumns.CONTENT_URI, projection, selection, selectionArgs, WaypointsColumns._ID)) {
|
||||
try (Cursor cursor = contentResolver.query(MarkerColumns.CONTENT_URI, projection, selection, selectionArgs, MarkerColumns._ID)) {
|
||||
if (cursor == null) {
|
||||
return 0;
|
||||
}
|
||||
@@ -541,26 +522,17 @@ public class ContentProviderUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a waypoint.
|
||||
*
|
||||
* @param waypoint the waypoint
|
||||
* @return the content provider URI of the inserted waypoint.
|
||||
* @return the content provider URI of the inserted marker.
|
||||
*/
|
||||
public Uri insertWaypoint(@NonNull Waypoint waypoint) {
|
||||
waypoint.setId(null);
|
||||
return contentResolver.insert(WaypointsColumns.CONTENT_URI, createContentValues(waypoint));
|
||||
public Uri insertMarker(@NonNull Marker marker) {
|
||||
marker.setId(null);
|
||||
return contentResolver.insert(MarkerColumns.CONTENT_URI, createContentValues(marker));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete waypoint's photo if any.
|
||||
*
|
||||
* @param context the context object.
|
||||
* @param waypoint the waypoint object.
|
||||
*/
|
||||
private void deleteWaypointPhoto(Context context, Waypoint waypoint) {
|
||||
if (waypoint != null && waypoint.hasPhoto()) {
|
||||
Uri uri = waypoint.getPhotoURI();
|
||||
File file = FileUtils.getPhotoFileIfExists(context, waypoint.getTrackId(), uri);
|
||||
private void deleteMarkerPhoto(Context context, Marker marker) {
|
||||
if (marker != null && marker.hasPhoto()) {
|
||||
Uri uri = marker.getPhotoURI();
|
||||
File file = FileUtils.getPhotoFileIfExists(context, marker.getTrackId(), uri);
|
||||
if (file.exists()) {
|
||||
File parent = file.getParentFile();
|
||||
file.delete();
|
||||
@@ -572,71 +544,67 @@ public class ContentProviderUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a waypoint.
|
||||
* Returns true if successful.
|
||||
*
|
||||
* @param updatedWaypoint the waypoint with updated data.
|
||||
* @param updateMarker the marker with updated data.
|
||||
* @return true if successful.
|
||||
*/
|
||||
public boolean updateWaypoint(Context context, Waypoint updatedWaypoint) {
|
||||
Waypoint savedWaypoint = getWaypoint(updatedWaypoint.getId());
|
||||
if (!updatedWaypoint.hasPhoto()) {
|
||||
deleteWaypointPhoto(context, savedWaypoint);
|
||||
public boolean updateMarker(Context context, Marker updateMarker) {
|
||||
Marker savedMarker = getMarker(updateMarker.getId());
|
||||
if (!updateMarker.hasPhoto()) {
|
||||
deleteMarkerPhoto(context, savedMarker);
|
||||
}
|
||||
int rows = contentResolver.update(WaypointsColumns.CONTENT_URI, createContentValues(updatedWaypoint), WaypointsColumns._ID + "=?", new String[]{Long.toString(updatedWaypoint.getId().getId())});
|
||||
int rows = contentResolver.update(MarkerColumns.CONTENT_URI, createContentValues(updateMarker), MarkerColumns._ID + "=?", new String[]{Long.toString(updateMarker.getId().getId())});
|
||||
return rows == 1;
|
||||
}
|
||||
|
||||
ContentValues createContentValues(@NonNull Waypoint waypoint) {
|
||||
ContentValues createContentValues(@NonNull Marker marker) {
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
if (waypoint.getId() != null && waypoint.getId().isValid()) {
|
||||
values.put(WaypointsColumns._ID, waypoint.getId().getId());
|
||||
if (marker.getId() != null && marker.getId().isValid()) {
|
||||
values.put(MarkerColumns._ID, marker.getId().getId());
|
||||
}
|
||||
values.put(WaypointsColumns.NAME, waypoint.getName());
|
||||
values.put(WaypointsColumns.DESCRIPTION, waypoint.getDescription());
|
||||
values.put(WaypointsColumns.CATEGORY, waypoint.getCategory());
|
||||
values.put(WaypointsColumns.ICON, waypoint.getIcon());
|
||||
if (waypoint.getTrackId() != null) {
|
||||
values.put(WaypointsColumns.TRACKID, waypoint.getTrackId().getId());
|
||||
values.put(MarkerColumns.NAME, marker.getName());
|
||||
values.put(MarkerColumns.DESCRIPTION, marker.getDescription());
|
||||
values.put(MarkerColumns.CATEGORY, marker.getCategory());
|
||||
values.put(MarkerColumns.ICON, marker.getIcon());
|
||||
if (marker.getTrackId() != null) {
|
||||
values.put(MarkerColumns.TRACKID, marker.getTrackId().getId());
|
||||
}
|
||||
values.put(WaypointsColumns.LENGTH, waypoint.getLength());
|
||||
values.put(WaypointsColumns.DURATION, waypoint.getDuration());
|
||||
values.put(MarkerColumns.LENGTH, marker.getLength());
|
||||
values.put(MarkerColumns.DURATION, marker.getDuration());
|
||||
|
||||
Location location = waypoint.getLocation();
|
||||
values.put(WaypointsColumns.LONGITUDE, (int) (location.getLongitude() * 1E6));
|
||||
values.put(WaypointsColumns.LATITUDE, (int) (location.getLatitude() * 1E6));
|
||||
values.put(WaypointsColumns.TIME, location.getTime());
|
||||
Location location = marker.getLocation();
|
||||
values.put(MarkerColumns.LONGITUDE, (int) (location.getLongitude() * 1E6));
|
||||
values.put(MarkerColumns.LATITUDE, (int) (location.getLatitude() * 1E6));
|
||||
values.put(MarkerColumns.TIME, location.getTime());
|
||||
if (location.hasAltitude()) {
|
||||
values.put(WaypointsColumns.ALTITUDE, location.getAltitude());
|
||||
values.put(MarkerColumns.ALTITUDE, location.getAltitude());
|
||||
}
|
||||
if (location.hasAccuracy()) {
|
||||
values.put(WaypointsColumns.ACCURACY, location.getAccuracy());
|
||||
values.put(MarkerColumns.ACCURACY, location.getAccuracy());
|
||||
}
|
||||
if (location.hasBearing()) {
|
||||
values.put(WaypointsColumns.BEARING, location.getBearing());
|
||||
values.put(MarkerColumns.BEARING, location.getBearing());
|
||||
}
|
||||
|
||||
values.put(WaypointsColumns.PHOTOURL, waypoint.getPhotoUrl());
|
||||
values.put(MarkerColumns.PHOTOURL, marker.getPhotoUrl());
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a waypoint cursor.
|
||||
*
|
||||
* @param projection the projection
|
||||
* @param selection the selection
|
||||
* @param selectionArgs the selection args
|
||||
* @param sortOrder the sort order
|
||||
* @param maxWaypoints the maximum number of waypoints
|
||||
* @param maxCount the maximum number of markers
|
||||
*/
|
||||
private Cursor getWaypointCursor(String[] projection, String selection, String[] selectionArgs, String sortOrder, int maxWaypoints) {
|
||||
private Cursor getMarkerCursor(String[] projection, String selection, String[] selectionArgs, String sortOrder, int maxCount) {
|
||||
if (sortOrder == null) {
|
||||
sortOrder = WaypointsColumns._ID;
|
||||
sortOrder = MarkerColumns._ID;
|
||||
}
|
||||
if (maxWaypoints >= 0) {
|
||||
sortOrder += " LIMIT " + maxWaypoints;
|
||||
if (maxCount >= 0) {
|
||||
sortOrder += " LIMIT " + maxCount;
|
||||
}
|
||||
return contentResolver.query(WaypointsColumns.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
|
||||
return contentResolver.query(MarkerColumns.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -680,6 +648,10 @@ public class ContentProviderUtils {
|
||||
trackPoint.setPower(cursor.getFloat(indexes.sensorPowerIndex));
|
||||
}
|
||||
|
||||
if (!cursor.isNull(indexes.elevationGainIndex)) {
|
||||
trackPoint.setElevationGain(cursor.getFloat(indexes.elevationGainIndex));
|
||||
}
|
||||
|
||||
return trackPoint;
|
||||
}
|
||||
|
||||
@@ -836,7 +808,7 @@ public class ContentProviderUtils {
|
||||
/**
|
||||
* Creates the {@link ContentValues} for a {@link TrackPoint}.
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
* @param trackPoint the trackPointstats_pace_km#87
|
||||
* @param trackId the track id
|
||||
*/
|
||||
private ContentValues createContentValues(TrackPoint trackPoint, Track.Id trackId) {
|
||||
@@ -868,6 +840,11 @@ public class ContentProviderUtils {
|
||||
if (trackPoint.hasPower()) {
|
||||
values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.getPower());
|
||||
}
|
||||
|
||||
if (trackPoint.hasElevationGain()) {
|
||||
values.put(TrackPointsColumns.ELEVATION_GAIN, trackPoint.getElevationGain());
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
+35
-46
@@ -33,12 +33,12 @@ import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
|
||||
/**
|
||||
* A {@link ContentProvider} that handles access to track points, tracks, and waypoints tables.
|
||||
* A {@link ContentProvider} that handles access to track points, tracks, and markers tables.
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
*/
|
||||
@@ -61,9 +61,9 @@ public class CustomContentProvider extends ContentProvider {
|
||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.CONTENT_URI.getPath(), UrlType.TRACKS.ordinal());
|
||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.CONTENT_URI.getPath() + "/*", UrlType.TRACKS_BY_ID.ordinal());
|
||||
|
||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, WaypointsColumns.CONTENT_URI.getPath(), UrlType.WAYPOINTS.ordinal());
|
||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, WaypointsColumns.CONTENT_URI.getPath() + "/#", UrlType.WAYPOINTS_BY_ID.ordinal());
|
||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, WaypointsColumns.CONTENT_URI_BY_TRACKID.getPath() + "/*", UrlType.WAYPOINTS_BY_TRACKID.ordinal());
|
||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, MarkerColumns.CONTENT_URI.getPath(), UrlType.MARKERS.ordinal());
|
||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, MarkerColumns.CONTENT_URI.getPath() + "/#", UrlType.MARKERS_BY_ID.ordinal());
|
||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, MarkerColumns.CONTENT_URI_BY_TRACKID.getPath() + "/*", UrlType.MARKERS_BY_TRACKID.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,8 +100,8 @@ public class CustomContentProvider extends ContentProvider {
|
||||
table = TracksColumns.TABLE_NAME;
|
||||
shouldVacuum = true;
|
||||
break;
|
||||
case WAYPOINTS:
|
||||
table = WaypointsColumns.TABLE_NAME;
|
||||
case MARKERS:
|
||||
table = MarkerColumns.TABLE_NAME;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
@@ -138,11 +138,11 @@ public class CustomContentProvider extends ContentProvider {
|
||||
return TracksColumns.CONTENT_TYPE;
|
||||
case TRACKS_BY_ID:
|
||||
return TracksColumns.CONTENT_ITEMTYPE;
|
||||
case WAYPOINTS:
|
||||
return WaypointsColumns.CONTENT_TYPE;
|
||||
case WAYPOINTS_BY_ID:
|
||||
case WAYPOINTS_BY_TRACKID:
|
||||
return WaypointsColumns.CONTENT_ITEMTYPE;
|
||||
case MARKERS:
|
||||
return MarkerColumns.CONTENT_TYPE;
|
||||
case MARKERS_BY_ID:
|
||||
case MARKERS_BY_TRACKID:
|
||||
return MarkerColumns.CONTENT_ITEMTYPE;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
}
|
||||
@@ -213,17 +213,17 @@ public class CustomContentProvider extends ContentProvider {
|
||||
queryBuilder.setTables(TracksColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere(TracksColumns._ID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
||||
break;
|
||||
case WAYPOINTS:
|
||||
queryBuilder.setTables(WaypointsColumns.TABLE_NAME);
|
||||
sortOrder = sort != null ? sort : WaypointsColumns.DEFAULT_SORT_ORDER;
|
||||
case MARKERS:
|
||||
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||
sortOrder = sort != null ? sort : MarkerColumns.DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
case WAYPOINTS_BY_ID:
|
||||
queryBuilder.setTables(WaypointsColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere(WaypointsColumns._ID + "=" + ContentUris.parseId(url));
|
||||
case MARKERS_BY_ID:
|
||||
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere(MarkerColumns._ID + "=" + ContentUris.parseId(url));
|
||||
break;
|
||||
case WAYPOINTS_BY_TRACKID:
|
||||
queryBuilder.setTables(WaypointsColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere(WaypointsColumns.TRACKID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
||||
case MARKERS_BY_TRACKID:
|
||||
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere(MarkerColumns.TRACKID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown url " + url);
|
||||
@@ -261,13 +261,13 @@ public class CustomContentProvider extends ContentProvider {
|
||||
whereClause += " AND (" + where + ")";
|
||||
}
|
||||
break;
|
||||
case WAYPOINTS:
|
||||
table = WaypointsColumns.TABLE_NAME;
|
||||
case MARKERS:
|
||||
table = MarkerColumns.TABLE_NAME;
|
||||
whereClause = where;
|
||||
break;
|
||||
case WAYPOINTS_BY_ID:
|
||||
table = WaypointsColumns.TABLE_NAME;
|
||||
whereClause = WaypointsColumns._ID + "=" + ContentUris.parseId(url);
|
||||
case MARKERS_BY_ID:
|
||||
table = MarkerColumns.TABLE_NAME;
|
||||
whereClause = MarkerColumns._ID + "=" + ContentUris.parseId(url);
|
||||
if (!TextUtils.isEmpty(where)) {
|
||||
whereClause += " AND (" + where + ")";
|
||||
}
|
||||
@@ -316,8 +316,8 @@ public class CustomContentProvider extends ContentProvider {
|
||||
return insertTrackPoint(url, contentValues);
|
||||
case TRACKS:
|
||||
return insertTrack(url, contentValues);
|
||||
case WAYPOINTS:
|
||||
return insertWaypoint(url, contentValues);
|
||||
case MARKERS:
|
||||
return insertMarker(url, contentValues);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown url " + url);
|
||||
}
|
||||
@@ -361,25 +361,14 @@ public class CustomContentProvider extends ContentProvider {
|
||||
throw new SQLException("Failed to insert a track " + url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a waypoint.
|
||||
*
|
||||
* @param url the content url
|
||||
* @param contentValues the content values
|
||||
*/
|
||||
private Uri insertWaypoint(Uri url, ContentValues contentValues) {
|
||||
long rowId = db.insert(WaypointsColumns.TABLE_NAME, WaypointsColumns._ID, contentValues);
|
||||
private Uri insertMarker(Uri url, ContentValues contentValues) {
|
||||
long rowId = db.insert(MarkerColumns.TABLE_NAME, MarkerColumns._ID, contentValues);
|
||||
if (rowId >= 0) {
|
||||
return ContentUris.appendId(WaypointsColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
return ContentUris.appendId(MarkerColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
}
|
||||
throw new SQLException("Failed to insert a waypoint " + url);
|
||||
throw new SQLException("Failed to insert a marker " + url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Types of url.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
@VisibleForTesting
|
||||
enum UrlType {
|
||||
TRACKPOINTS,
|
||||
@@ -387,8 +376,8 @@ public class CustomContentProvider extends ContentProvider {
|
||||
TRACKPOINTS_BY_TRACKID,
|
||||
TRACKS,
|
||||
TRACKS_BY_ID,
|
||||
WAYPOINTS,
|
||||
WAYPOINTS_BY_ID,
|
||||
WAYPOINTS_BY_TRACKID
|
||||
MARKERS,
|
||||
MARKERS_BY_ID,
|
||||
MARKERS_BY_TRACKID
|
||||
}
|
||||
}
|
||||
|
||||
+35
-5
@@ -11,10 +11,10 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||
import de.dennisguse.opentracks.util.UUIDUtils;
|
||||
|
||||
/**
|
||||
@@ -25,7 +25,7 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String TAG = CustomSQLiteOpenHelper.class.getSimpleName();
|
||||
|
||||
private static final int DATABASE_VERSION = 26;
|
||||
private static final int DATABASE_VERSION = 27;
|
||||
|
||||
@VisibleForTesting
|
||||
public static final String DATABASE_NAME = "database.db";
|
||||
@@ -52,8 +52,8 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(TracksColumns.CREATE_TABLE);
|
||||
db.execSQL(TracksColumns.CREATE_TABLE_INDEX);
|
||||
|
||||
db.execSQL(WaypointsColumns.CREATE_TABLE);
|
||||
db.execSQL(WaypointsColumns.CREATE_TABLE_INDEX);
|
||||
db.execSQL(MarkerColumns.CREATE_TABLE);
|
||||
db.execSQL(MarkerColumns.CREATE_TABLE_INDEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,6 +70,10 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
||||
case 26:
|
||||
upgradeFrom25to26(db);
|
||||
break;
|
||||
case 27:
|
||||
upgradeFrom26to27(db);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Not implemented: upgrade to " + toVersion);
|
||||
@@ -91,6 +95,9 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
||||
case 25:
|
||||
downgradeFrom26to25(db);
|
||||
break;
|
||||
case 26:
|
||||
downgradeFrom27to26(db);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Not implemented: downgrade to " + toVersion);
|
||||
@@ -166,7 +173,7 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
||||
Track.Id trackId = new Track.Id(cursor.getLong(trackIdIndex));
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("uuid", UUIDUtils.toBytes(UUID.randomUUID()));
|
||||
db.update("tracks", cv, "_id = ?", new String[]{String.valueOf(trackId)});
|
||||
db.update("tracks", cv, "_id = ?", new String[]{String.valueOf(trackId.getId())});
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
}
|
||||
@@ -190,4 +197,27 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
private void upgradeFrom26to27(SQLiteDatabase db) {
|
||||
db.beginTransaction();
|
||||
|
||||
db.execSQL("ALTER TABLE trackpoints ADD COLUMN elevation_gain FLOAT");
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
private void downgradeFrom27to26(SQLiteDatabase db) {
|
||||
db.beginTransaction();
|
||||
|
||||
db.execSQL("ALTER TABLE trackpoints RENAME TO trackpoints_old");
|
||||
db.execSQL("CREATE TABLE trackpoints (_id INTEGER PRIMARY KEY AUTOINCREMENT, trackid INTEGER, longitude INTEGER, latitude INTEGER, time INTEGER, elevation FLOAT, accuracy FLOAT, speed FLOAT, bearing FLOAT, sensor_heartrate FLOAT, sensor_cadence FLOAT, sensor_power FLOAT)");
|
||||
db.execSQL("INSERT INTO trackpoints SELECT _id, trackid, longitude, latitude, time, elevation, accuracy, speed, bearing, sensor_heartrate, sensor_cadence, sensor_power FROM trackpoints_old");
|
||||
db.execSQL("DROP TABLE trackpoints_old");
|
||||
|
||||
db.execSQL("CREATE INDEX trackpoints_trackid_index ON trackpoints(trackid)");
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ import de.dennisguse.opentracks.chart.ChartPoint;
|
||||
import de.dennisguse.opentracks.chart.ChartView;
|
||||
import de.dennisguse.opentracks.content.TrackDataHub;
|
||||
import de.dennisguse.opentracks.content.TrackDataListener;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
@@ -242,21 +242,21 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWaypoints() {
|
||||
public void clearMarkers() {
|
||||
if (isResumed()) {
|
||||
chartView.clearWaypoints();
|
||||
chartView.clearMarker();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypoint(Waypoint waypoint) {
|
||||
if (isResumed() && waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) {
|
||||
chartView.addWaypoint(waypoint);
|
||||
public void onNewMarker(Marker marker) {
|
||||
if (isResumed() && marker != null && LocationUtils.isValidLocation(marker.getLocation())) {
|
||||
chartView.addMarker(marker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypointsDone() {
|
||||
public void onNewMarkersDone() {
|
||||
if (isResumed()) {
|
||||
runOnUiThread(updateChart);
|
||||
}
|
||||
|
||||
+3
-1
@@ -22,6 +22,8 @@ import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
@@ -76,7 +78,7 @@ class ChooseActivityTypeImageAdapter extends BaseAdapter {
|
||||
}
|
||||
|
||||
if (position == selected) {
|
||||
imageView.setBackgroundResource(R.drawable.list_selector_background_transition_holo_dark);
|
||||
imageView.setBackgroundColor(ContextCompat.getColor(parent.getContext(), R.color.colorAccent));
|
||||
} else {
|
||||
imageView.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.util.DialogUtils;
|
||||
|
||||
@@ -42,9 +42,9 @@ public class DeleteMarkerDialogFragment extends DialogFragment {
|
||||
|
||||
private DeleteMarkerCaller caller;
|
||||
|
||||
public static void showDialog(FragmentManager fragmentManager, Waypoint.Id... waypointIds) {
|
||||
public static void showDialog(FragmentManager fragmentManager, Marker.Id... markerIds) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelableArray(KEY_MARKER_IDS, waypointIds);
|
||||
bundle.putParcelableArray(KEY_MARKER_IDS, markerIds);
|
||||
|
||||
DeleteMarkerDialogFragment deleteMarkerDialogFragment = new DeleteMarkerDialogFragment();
|
||||
deleteMarkerDialogFragment.setArguments(bundle);
|
||||
@@ -64,23 +64,23 @@ public class DeleteMarkerDialogFragment extends DialogFragment {
|
||||
@Override
|
||||
@NonNull
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Waypoint.Id[] waypointIds = (Waypoint.Id[]) getArguments().getParcelableArray(KEY_MARKER_IDS);
|
||||
final Marker.Id[] markerIds = (Marker.Id[]) getArguments().getParcelableArray(KEY_MARKER_IDS);
|
||||
|
||||
final FragmentActivity fragmentActivity = getActivity();
|
||||
int titleId;
|
||||
int messageId;
|
||||
if (waypointIds == null) {
|
||||
if (markerIds == null) {
|
||||
titleId = R.string.generic_delete_all_confirm_title;
|
||||
messageId = R.string.marker_delete_all_confirm_message;
|
||||
} else {
|
||||
titleId = waypointIds.length > 1 ? R.string.generic_delete_selected_confirm_title : R.string.marker_delete_one_confirm_title;
|
||||
messageId = waypointIds.length > 1 ? R.string.marker_delete_multiple_confirm_message : R.string.marker_delete_one_confirm_message;
|
||||
titleId = markerIds.length > 1 ? R.string.generic_delete_selected_confirm_title : R.string.marker_delete_one_confirm_title;
|
||||
messageId = markerIds.length > 1 ? R.string.marker_delete_multiple_confirm_message : R.string.marker_delete_one_confirm_message;
|
||||
}
|
||||
return DialogUtils.createConfirmationDialog(
|
||||
fragmentActivity, titleId, getString(messageId), (dialog, which) -> new Thread(() -> {
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(fragmentActivity);
|
||||
for (Waypoint.Id waypointId : waypointIds) {
|
||||
contentProviderUtils.deleteWaypoint(getContext(), waypointId);
|
||||
for (Marker.Id markerId : markerIds) {
|
||||
contentProviderUtils.deleteMarker(getContext(), markerId);
|
||||
}
|
||||
caller.onDeleteMarkerDone();
|
||||
}).start());
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
package de.dennisguse.opentracks.fragments;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
|
||||
+13
-13
@@ -38,6 +38,7 @@ import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.io.file.ExportFile;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
import de.dennisguse.opentracks.util.DialogUtils;
|
||||
@@ -208,33 +209,32 @@ public class ExportProgressDialogFragment extends DialogFragment {
|
||||
private Boolean exportTrack(Context context, Track track) {
|
||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
||||
|
||||
//TODO Move to helper function
|
||||
String fileName = track.getId() + "." + trackFileFormat.getExtension();
|
||||
DocumentFile exportDocumentFile = ExportFile.getExportDocumentFile(
|
||||
track.getId(),
|
||||
trackFileFormat.getExtension(),
|
||||
directory,
|
||||
trackFileFormat.getMimeType()
|
||||
);
|
||||
|
||||
// Overwrite a file if it exists; DocumentFile.createFile() creates a new file appending a suffix if the displayname already exists.
|
||||
DocumentFile file = directory.findFile(fileName);
|
||||
if (file == null) {
|
||||
file = directory.createFile(trackFileFormat.getMimeType(), fileName);
|
||||
}
|
||||
|
||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(file.getUri())) {
|
||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(exportDocumentFile.getUri())) {
|
||||
if (trackExporter.writeTrack(track, outputStream)) {
|
||||
return true;
|
||||
} else {
|
||||
if (!file.delete()) {
|
||||
Log.e(TAG, "Unable to delete file");
|
||||
if (!exportDocumentFile.delete()) {
|
||||
Log.e(TAG, "Unable to delete exportDocumentFile");
|
||||
}
|
||||
Log.e(TAG, "Unable to export track");
|
||||
return false;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "Unable to open file " + file.getName(), e);
|
||||
Log.e(TAG, "Unable to open exportDocumentFile " + exportDocumentFile.getName(), e);
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to close file output stream", e);
|
||||
Log.e(TAG, "Unable to close exportDocumentFile output stream", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface DismissCallback {
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
package de.dennisguse.opentracks.fragments;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
package de.dennisguse.opentracks.fragments;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.TrackRecordingActivity;
|
||||
import de.dennisguse.opentracks.adapters.IntervalStatisticsAdapter;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel;
|
||||
|
||||
/**
|
||||
* A fragment to display the intervals from recorded track.
|
||||
*/
|
||||
public class IntervalsFragment extends Fragment {
|
||||
|
||||
private static final String TAG = IntervalsFragment.class.getSimpleName();
|
||||
|
||||
private static final String TRACK_ID_KEY = "trackId";
|
||||
|
||||
private IntervalStatisticsModel viewModel;
|
||||
private ListView intervalListView;
|
||||
protected IntervalStatisticsAdapter.StackMode stackModeListView;
|
||||
private IntervalStatisticsModel.IntervalOption selectedInterval;
|
||||
|
||||
private String intervalUnit;
|
||||
private IntervalStatisticsAdapter adapter;
|
||||
protected Spinner spinnerIntervals;
|
||||
private ArrayAdapter<IntervalStatisticsModel.IntervalOption> spinnerAdapter;
|
||||
|
||||
private Track.Id trackId;
|
||||
|
||||
protected final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (preferences, key) -> {
|
||||
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
|
||||
intervalUnit = PreferencesUtils.isMetricUnits(getContext()) ? getContext().getString(R.string.unit_kilometer) : getContext().getString(R.string.unit_mile);
|
||||
if (adapter != null) {
|
||||
adapter.notifyDataSetChanged();
|
||||
spinnerAdapter.notifyDataSetChanged();
|
||||
intervalChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static Fragment newInstance(Track.Id trackId) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(TRACK_ID_KEY, trackId);
|
||||
|
||||
Fragment fragment = new IntervalsFragment();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.interval_list_view, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
|
||||
intervalUnit = PreferencesUtils.isMetricUnits(getContext()) ? getContext().getString(R.string.unit_kilometer) : getContext().getString(R.string.unit_mile);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
trackId = savedInstanceState.getParcelable(TRACK_ID_KEY);
|
||||
} else {
|
||||
trackId = getArguments().getParcelable(TRACK_ID_KEY);
|
||||
}
|
||||
|
||||
intervalListView = view.findViewById(R.id.interval_list);
|
||||
intervalListView.setEmptyView(view.findViewById(R.id.interval_list_empty_view));
|
||||
|
||||
stackModeListView = IntervalStatisticsAdapter.StackMode.STACK_FROM_TOP;
|
||||
|
||||
viewModel = new ViewModelProvider(this).get(IntervalStatisticsModel.class);
|
||||
|
||||
spinnerIntervals = view.findViewById(R.id.spinner_intervals);
|
||||
|
||||
spinnerAdapter = new ArrayAdapter<IntervalStatisticsModel.IntervalOption>(getContext(), android.R.layout.simple_spinner_dropdown_item, IntervalStatisticsModel.IntervalOption.values()) {
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
TextView v = (TextView) super.getView(position, convertView, parent);
|
||||
v.setText(v.getText() + " " + intervalUnit);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
TextView v = (TextView) super.getDropDownView(position, convertView, parent);
|
||||
v.setText(v.getText() + " " + intervalUnit);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
spinnerIntervals.setAdapter(spinnerAdapter);
|
||||
|
||||
spinnerIntervals.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
selectedInterval = IntervalStatisticsModel.IntervalOption.values()[i];
|
||||
intervalChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
intervalChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
PreferencesUtils.unregister(getContext(), sharedPreferenceChangeListener);
|
||||
|
||||
intervalListView = null;
|
||||
adapter = null;
|
||||
spinnerIntervals = null;
|
||||
viewModel = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putParcelable(TRACK_ID_KEY, trackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update intervals through {@link IntervalStatisticsModel} view model.
|
||||
*/
|
||||
public void intervalChanged() {
|
||||
if (viewModel == null || intervalListView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
LiveData<IntervalStatistics> liveData = viewModel.getIntervalStats(trackId, selectedInterval);
|
||||
liveData.observe(getActivity(), intervalStatistics -> {
|
||||
if (intervalStatistics != null) {
|
||||
adapter = new IntervalStatisticsAdapter(getContext(), intervalStatistics.getIntervalList(), stackModeListView);
|
||||
intervalListView.setAdapter(adapter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setTrackId(Track.Id trackId) {
|
||||
this.trackId = trackId;
|
||||
}
|
||||
|
||||
public static class IntervalsRecordingFragment extends IntervalsFragment implements TrackRecordingActivity.OnTrackIdListener {
|
||||
// Refreshing intervals stats it's not so demanding so 5 seconds is enough to balance performance and user experience.
|
||||
private static final long UI_UPDATE_INTERVAL = 5 * UnitConversions.ONE_SECOND_MS;
|
||||
|
||||
private Handler intervalHandler;
|
||||
|
||||
private final Runnable intervalRunner = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isResumed()) {
|
||||
updateIntervals();
|
||||
intervalHandler.postDelayed(intervalRunner, UI_UPDATE_INTERVAL);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static Fragment newInstance(Track.Id trackId) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(TRACK_ID_KEY, trackId);
|
||||
|
||||
Fragment fragment = new IntervalsRecordingFragment();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
((TrackRecordingActivity) getActivity()).setTrackIdListener(this);
|
||||
intervalHandler = new Handler();
|
||||
stackModeListView = IntervalStatisticsAdapter.StackMode.STACK_FROM_BOTTOM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
intervalHandler.post(intervalRunner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
intervalHandler.removeCallbacks(intervalRunner);
|
||||
}
|
||||
|
||||
private void updateIntervals() {
|
||||
intervalChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackId(Track.Id trackId) {
|
||||
setTrackId(trackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import de.dennisguse.opentracks.MarkerEditActivity;
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.ListItemUtils;
|
||||
@@ -66,8 +66,8 @@ public class MarkerDetailFragment extends Fragment {
|
||||
private Handler handler;
|
||||
private ImageView photoView;
|
||||
private ImageView textGradient;
|
||||
private LinearLayout waypointInfo;
|
||||
private Waypoint waypoint;
|
||||
private LinearLayout markerInfo;
|
||||
private Marker marker;
|
||||
private final Runnable hideText = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -85,17 +85,17 @@ public class MarkerDetailFragment extends Fragment {
|
||||
@Override
|
||||
public void onAnimationEnd(Animation anim) {
|
||||
textGradient.setVisibility(View.GONE);
|
||||
waypointInfo.setVisibility(View.GONE);
|
||||
markerInfo.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
textGradient.startAnimation(animation);
|
||||
waypointInfo.startAnimation(animation);
|
||||
markerInfo.startAnimation(animation);
|
||||
}
|
||||
};
|
||||
|
||||
public static MarkerDetailFragment newInstance(Waypoint.Id waypointId) {
|
||||
public static MarkerDetailFragment newInstance(Marker.Id markerId) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(KEY_MARKER_ID, waypointId);
|
||||
bundle.putParcelable(KEY_MARKER_ID, markerId);
|
||||
|
||||
MarkerDetailFragment fragment = new MarkerDetailFragment();
|
||||
fragment.setArguments(bundle);
|
||||
@@ -106,8 +106,8 @@ public class MarkerDetailFragment extends Fragment {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Waypoint.Id waypointId = getArguments().getParcelable(KEY_MARKER_ID);
|
||||
if (waypointId == null) {
|
||||
Marker.Id markerId = getArguments().getParcelable(KEY_MARKER_ID);
|
||||
if (markerId == null) {
|
||||
Log.d(TAG, "invalid marker id");
|
||||
getParentFragmentManager().popBackStack();
|
||||
return;
|
||||
@@ -121,15 +121,15 @@ public class MarkerDetailFragment extends Fragment {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.marker_detail_fragment, container, false);
|
||||
|
||||
photoView = view.findViewById(R.id.marker_detail_waypoint_photo);
|
||||
textGradient = view.findViewById(R.id.marker_detail_waypoint_text_gradient);
|
||||
waypointInfo = view.findViewById(R.id.marker_detail_waypoint_info);
|
||||
photoView = view.findViewById(R.id.marker_detail_marker_photo);
|
||||
textGradient = view.findViewById(R.id.marker_detail_marker_text_gradient);
|
||||
markerInfo = view.findViewById(R.id.marker_detail_marker_info);
|
||||
|
||||
photoView.setOnClickListener(v -> {
|
||||
handler.removeCallbacks(hideText);
|
||||
int visibility = waypointInfo.getVisibility() == View.GONE ? View.VISIBLE : View.GONE;
|
||||
int visibility = markerInfo.getVisibility() == View.GONE ? View.VISIBLE : View.GONE;
|
||||
textGradient.setVisibility(visibility);
|
||||
waypointInfo.setVisibility(visibility);
|
||||
markerInfo.setVisibility(visibility);
|
||||
if (visibility == View.VISIBLE) {
|
||||
handler.postDelayed(hideText, HIDE_TEXT_DELAY);
|
||||
}
|
||||
@@ -141,8 +141,8 @@ public class MarkerDetailFragment extends Fragment {
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// Need to update the waypoint in case returning after an edit
|
||||
updateWaypoint(true);
|
||||
// Need to update the marker in case returning after an edit
|
||||
updateMarker(true);
|
||||
updateUi();
|
||||
updateMenuItems();
|
||||
}
|
||||
@@ -171,64 +171,59 @@ public class MarkerDetailFragment extends Fragment {
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.marker_detail, menu);
|
||||
shareMarkerImageMenuItem = menu.findItem(R.id.marker_detail_share);
|
||||
updateWaypoint(false);
|
||||
updateMarker(false);
|
||||
updateMenuItems();
|
||||
}
|
||||
|
||||
private void updateMenuItems() {
|
||||
if (shareMarkerImageMenuItem != null)
|
||||
shareMarkerImageMenuItem.setVisible(waypoint.hasPhoto());
|
||||
shareMarkerImageMenuItem.setVisible(marker.hasPhoto());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
Waypoint.Id waypointId = getArguments().getParcelable(KEY_MARKER_ID); //TODO Should only happen in onCreate?
|
||||
Marker.Id markerId = getArguments().getParcelable(KEY_MARKER_ID); //TODO Should only happen in onCreate?
|
||||
FragmentActivity fragmentActivity = getActivity();
|
||||
Intent intent;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.marker_detail_show_on_map:
|
||||
IntentUtils.showCoordinateOnMap(getContext(), waypoint);
|
||||
IntentUtils.showCoordinateOnMap(getContext(), marker);
|
||||
return true;
|
||||
case R.id.marker_detail_edit:
|
||||
intent = IntentUtils.newIntent(fragmentActivity, MarkerEditActivity.class)
|
||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, waypointId);
|
||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.marker_detail_share:
|
||||
if (waypoint.hasPhoto()) {
|
||||
intent = IntentUtils.newShareImageIntent(getContext(), waypoint.getPhotoURI());
|
||||
if (marker.hasPhoto()) {
|
||||
intent = IntentUtils.newShareImageIntent(getContext(), marker.getPhotoURI());
|
||||
intent = Intent.createChooser(intent, null);
|
||||
startActivity(intent);
|
||||
}
|
||||
return true;
|
||||
case R.id.marker_detail_delete:
|
||||
DeleteMarkerDialogFragment.showDialog(getChildFragmentManager(), waypointId);
|
||||
DeleteMarkerDialogFragment.showDialog(getChildFragmentManager(), markerId);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the waypoint.
|
||||
*
|
||||
* @param refresh true to always update
|
||||
*/
|
||||
private void updateWaypoint(boolean refresh) {
|
||||
if (refresh || waypoint == null) {
|
||||
waypoint = contentProviderUtils.getWaypoint(getArguments().getParcelable(KEY_MARKER_ID)); //TODO Should only happen in onCreate?
|
||||
if (waypoint == null) {
|
||||
Log.d(TAG, "waypoint is null");
|
||||
private void updateMarker(boolean refresh) {
|
||||
if (refresh || marker == null) {
|
||||
marker = contentProviderUtils.getMarker(getArguments().getParcelable(KEY_MARKER_ID)); //TODO Should only happen in onCreate?
|
||||
if (marker == null) {
|
||||
Log.d(TAG, "marker is null");
|
||||
getParentFragmentManager().popBackStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUi() {
|
||||
boolean hasPhoto = waypoint.hasPhoto();
|
||||
boolean hasPhoto = marker.hasPhoto();
|
||||
if (hasPhoto) {
|
||||
handler.removeCallbacks(hideText);
|
||||
photoView.setImageURI(waypoint.getPhotoURI());
|
||||
photoView.setImageURI(marker.getPhotoURI());
|
||||
handler.postDelayed(hideText, HIDE_TEXT_DELAY);
|
||||
} else {
|
||||
photoView.setImageResource(MarkerUtils.ICON_ID);
|
||||
@@ -236,23 +231,23 @@ public class MarkerDetailFragment extends Fragment {
|
||||
|
||||
setName(hasPhoto);
|
||||
|
||||
TextView category = getView().findViewById(R.id.marker_detail_waypoint_category);
|
||||
ListItemUtils.setTextView(getActivity(), category, StringUtils.getCategory(waypoint.getCategory()), hasPhoto);
|
||||
TextView category = getView().findViewById(R.id.marker_detail_marker_category);
|
||||
ListItemUtils.setTextView(getActivity(), category, StringUtils.getCategory(marker.getCategory()), hasPhoto);
|
||||
|
||||
TextView description = getView().findViewById(R.id.marker_detail_waypoint_description);
|
||||
ListItemUtils.setTextView(getActivity(), description, waypoint.getDescription(), hasPhoto);
|
||||
TextView description = getView().findViewById(R.id.marker_detail_marker_description);
|
||||
ListItemUtils.setTextView(getActivity(), description, marker.getDescription(), hasPhoto);
|
||||
|
||||
setLocation(hasPhoto);
|
||||
}
|
||||
|
||||
private void setName(boolean addShadow) {
|
||||
TextView textView = getView().findViewById(R.id.marker_detail_waypoint_name);
|
||||
ListItemUtils.setTextView(getActivity(), textView, waypoint.getName(), addShadow);
|
||||
TextView textView = getView().findViewById(R.id.marker_detail_marker_name);
|
||||
ListItemUtils.setTextView(getActivity(), textView, marker.getName(), addShadow);
|
||||
}
|
||||
|
||||
private void setLocation(boolean addShadow) {
|
||||
TextView textView = getView().findViewById(R.id.marker_detail_waypoint_location);
|
||||
Location location = waypoint.getLocation();
|
||||
TextView textView = getView().findViewById(R.id.marker_detail_marker_location);
|
||||
Location location = marker.getLocation();
|
||||
String value;
|
||||
if (location == null) {
|
||||
value = null;
|
||||
|
||||
@@ -19,25 +19,21 @@ package de.dennisguse.opentracks.fragments;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.util.Pair;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.Group;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.TrackRecordedActivity;
|
||||
import de.dennisguse.opentracks.content.TrackDataHub;
|
||||
import de.dennisguse.opentracks.content.TrackDataListener;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
@@ -49,10 +45,14 @@ import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class StatisticsRecordedFragment extends Fragment implements TrackDataListener {
|
||||
public class StatisticsRecordedFragment extends Fragment {
|
||||
|
||||
private TrackStatistics trackStatistics = null;
|
||||
private static final String TRACK_ID_KEY = "trackId";
|
||||
|
||||
private TrackStatistics trackStatistics;
|
||||
private String category = "";
|
||||
private Track.Id trackId;
|
||||
private ContentProviderUtils contentProviderUtils;
|
||||
|
||||
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (preferences, key) -> {
|
||||
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
|
||||
@@ -71,12 +71,11 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
||||
return inflater.inflate(R.layout.statistics_recorded, container, false);
|
||||
}
|
||||
|
||||
/* Views */
|
||||
private TextView totalTimeValueView;
|
||||
private TextView distanceValue;
|
||||
private TextView distanceUnit;
|
||||
private View activityLabel;
|
||||
private Spinner activitySpinner;
|
||||
private ImageView activitySpinner;
|
||||
private TextView movingTimeValue;
|
||||
private TextView speedAvgLabel;
|
||||
private TextView speedAvgValue;
|
||||
@@ -88,6 +87,27 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
||||
private TextView speedMovingValue;
|
||||
private TextView speedMovingUnit;
|
||||
|
||||
private Group elevationGroup;
|
||||
private TextView elevationTotalGainValue;
|
||||
private TextView elevationTotalGainUnit;
|
||||
|
||||
public static StatisticsRecordedFragment newInstance(Track.Id trackId) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(TRACK_ID_KEY, trackId);
|
||||
|
||||
StatisticsRecordedFragment fragment = new StatisticsRecordedFragment();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
trackId = getArguments().getParcelable(TRACK_ID_KEY);
|
||||
contentProviderUtils = new ContentProviderUtils(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
@@ -113,26 +133,10 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
||||
speedMovingLabel = view.findViewById(R.id.stats_moving_speed_label);
|
||||
speedMovingValue = view.findViewById(R.id.stats_moving_speed_value);
|
||||
speedMovingUnit = view.findViewById(R.id.stats_moving_speed_unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
Spinner activityTypeIcon = getView().findViewById(R.id.stats_activity_type_icon);
|
||||
activityTypeIcon.setAdapter(TrackIconUtils.getIconSpinnerAdapter(getActivity(), ""));
|
||||
activityTypeIcon.setOnTouchListener((v, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
((TrackRecordedActivity) getActivity()).chooseActivityType(category);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
activityTypeIcon.setOnKeyListener((v, keyCode, event) -> {
|
||||
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||
((TrackRecordedActivity) getActivity()).chooseActivityType(category);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
elevationGroup = view.findViewById(R.id.stats_elevation_group);
|
||||
elevationTotalGainValue = view.findViewById(R.id.stats_elevation_gain_value);
|
||||
elevationTotalGainUnit = view.findViewById(R.id.stats_elevation_gain_unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -140,23 +144,15 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
||||
super.onResume();
|
||||
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
|
||||
|
||||
TrackDataHub trackDataHub = ((TrackRecordedActivity) getActivity()).getTrackDataHub();
|
||||
trackDataHub.registerTrackDataListener(this, true, false, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
PreferencesUtils.unregister(getContext(), sharedPreferenceChangeListener);
|
||||
|
||||
TrackDataHub trackDataHub = ((TrackRecordedActivity) getActivity()).getTrackDataHub();
|
||||
trackDataHub.unregisterTrackDataListener(this);
|
||||
loadStatistics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
PreferencesUtils.unregister(getContext(), sharedPreferenceChangeListener);
|
||||
|
||||
totalTimeValueView = null;
|
||||
|
||||
distanceValue = null;
|
||||
@@ -178,13 +174,17 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
||||
speedMovingLabel = null;
|
||||
speedMovingValue = null;
|
||||
speedMovingUnit = null;
|
||||
|
||||
elevationGroup = null;
|
||||
elevationTotalGainValue = null;
|
||||
elevationTotalGainUnit = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackUpdated(final Track track) {
|
||||
public void loadStatistics() {
|
||||
if (isResumed()) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
if (isResumed()) {
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
trackStatistics = track != null ? track.getTrackStatistics() : null;
|
||||
category = track != null ? track.getCategory() : "";
|
||||
updateUI();
|
||||
@@ -193,44 +193,7 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTrackPoints() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledInTrackPoint(TrackPoint trackPoint) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledOutTrackPoint(TrackPoint trackPoint) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTrackPointsDone() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWaypoints() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypoint(Waypoint wpt) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypointsDone() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
String trackIconValue = TrackIconUtils.getIconValue(getContext(), category);
|
||||
|
||||
boolean metricUnits = PreferencesUtils.isMetricUnits(getContext());
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(getContext(), category);
|
||||
|
||||
@@ -245,12 +208,14 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
||||
|
||||
// Set activity type
|
||||
{
|
||||
String trackIconValue = TrackIconUtils.getIconValue(getContext(), category);
|
||||
|
||||
activityLabel.setVisibility(trackIconValue != null ? View.VISIBLE : View.GONE);
|
||||
|
||||
activitySpinner.setVisibility(trackIconValue != null ? View.VISIBLE : View.GONE);
|
||||
activitySpinner.setEnabled(false);
|
||||
if (trackIconValue != null) {
|
||||
TrackIconUtils.setIconSpinner(activitySpinner, trackIconValue);
|
||||
activitySpinner.setImageDrawable(ContextCompat.getDrawable(getContext(), TrackIconUtils.getIconDrawable(trackIconValue)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,5 +256,18 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
||||
speedMovingValue.setText(parts.first);
|
||||
speedMovingUnit.setText(parts.second);
|
||||
}
|
||||
|
||||
// Set elevation gain
|
||||
{
|
||||
// Make elevation visible?
|
||||
boolean showElevation = PreferencesUtils.isShowStatsElevation(getContext());
|
||||
elevationGroup.setVisibility(showElevation ? View.VISIBLE : View.GONE);
|
||||
|
||||
Float elevationGain_m = trackStatistics != null ? trackStatistics.getTotalElevationGain() : null;
|
||||
|
||||
Pair<String, String> parts = StringUtils.formatElevation(getContext(), elevationGain_m, metricUnits);
|
||||
elevationTotalGainValue.setText(parts.first);
|
||||
elevationTotalGainUnit.setText(parts.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.TrackRecordingActivity;
|
||||
import de.dennisguse.opentracks.content.TrackDataHub;
|
||||
import de.dennisguse.opentracks.content.TrackDataListener;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
|
||||
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||
@@ -55,13 +55,17 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
|
||||
private TrackRecordingServiceConnection trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
||||
|
||||
private TrackPoint lastTrackPoint = null;
|
||||
private TrackStatistics lastTrackStatistics = null;
|
||||
private TrackPoint lastTrackPoint;
|
||||
private TrackStatistics lastTrackStatistics;
|
||||
|
||||
private String category = "";
|
||||
@Deprecated //TODO This should be handled somewhere else; not in the UI.
|
||||
private int recordingGpsAccuracy;
|
||||
|
||||
public static Fragment newInstance() {
|
||||
return new StatisticsRecordingFragment();
|
||||
}
|
||||
|
||||
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||
@@ -128,12 +132,14 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
private TextView speedMovingLabel;
|
||||
private TextView speedMovingValue;
|
||||
private TextView speedMovingUnit;
|
||||
private Group elevationGroup;
|
||||
private TextView speedLabel;
|
||||
private TextView speedValue;
|
||||
private TextView speedUnit;
|
||||
private TextView elevationValue;
|
||||
private TextView elevationUnit;
|
||||
private Group elevationGroup;
|
||||
private TextView elevationCurrentValue;
|
||||
private TextView elevationCurrentUnit;
|
||||
private TextView elevationTotalGainValue;
|
||||
private TextView elevationTotalGainUnit;
|
||||
private Group coordinateGroup;
|
||||
private TextView latitudeValue;
|
||||
private TextView longitudeValue;
|
||||
@@ -174,14 +180,16 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
speedMovingValue = view.findViewById(R.id.stats_moving_speed_value);
|
||||
speedMovingUnit = view.findViewById(R.id.stats_moving_speed_unit);
|
||||
|
||||
elevationGroup = view.findViewById(R.id.stats_elevation_current_group);
|
||||
|
||||
speedLabel = view.findViewById(R.id.stats_speed_label);
|
||||
speedValue = view.findViewById(R.id.stats_speed_value);
|
||||
speedUnit = view.findViewById(R.id.stats_speed_unit);
|
||||
|
||||
elevationValue = view.findViewById(R.id.stats_elevation_current_value);
|
||||
elevationUnit = view.findViewById(R.id.stats_elevation_current_unit);
|
||||
elevationGroup = view.findViewById(R.id.stats_elevation_group);
|
||||
elevationCurrentValue = view.findViewById(R.id.stats_elevation_current_value);
|
||||
elevationCurrentUnit = view.findViewById(R.id.stats_elevation_current_unit);
|
||||
|
||||
elevationTotalGainValue = view.findViewById(R.id.stats_elevation_gain_value);
|
||||
elevationTotalGainUnit = view.findViewById(R.id.stats_elevation_gain_unit);
|
||||
|
||||
coordinateGroup = view.findViewById(R.id.stats_coordinate_group);
|
||||
|
||||
@@ -193,7 +201,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
recordingGpsAccuracy = Integer.parseInt(getContext().getResources().getString(R.string.recording_gps_accuracy_default));
|
||||
recordingGpsAccuracy = Integer.parseInt(getResources().getString(R.string.recording_gps_accuracy_default));
|
||||
|
||||
handlerUpdateUI = new Handler();
|
||||
|
||||
@@ -272,14 +280,16 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
speedMovingValue = null;
|
||||
speedMovingUnit = null;
|
||||
|
||||
elevationGroup = null;
|
||||
|
||||
speedLabel = null;
|
||||
speedValue = null;
|
||||
speedUnit = null;
|
||||
|
||||
elevationValue = null;
|
||||
elevationUnit = null;
|
||||
elevationGroup = null;
|
||||
elevationCurrentValue = null;
|
||||
elevationCurrentUnit = null;
|
||||
|
||||
elevationTotalGainValue = null;
|
||||
elevationTotalGainUnit = null;
|
||||
|
||||
coordinateGroup = null;
|
||||
|
||||
@@ -346,17 +356,17 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWaypoints() {
|
||||
public void clearMarkers() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypoint(Waypoint wpt) {
|
||||
public void onNewMarker(Marker marker) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypointsDone() {
|
||||
public void onNewMarkersDone() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@@ -402,20 +412,25 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
|
||||
/**
|
||||
* Tries to fetch most recent {@link SensorDataSet} from {@link de.dennisguse.opentracks.services.TrackRecordingService}.
|
||||
* Also sets elevation gain.
|
||||
*/
|
||||
private void updateSensorDataUI() {
|
||||
TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
|
||||
|
||||
SensorDataSet sensorDataSet = null;
|
||||
Float elevationGain_m = null;
|
||||
if (trackRecordingService == null) {
|
||||
Log.d(TAG, "Cannot get the track recording service.");
|
||||
} else {
|
||||
sensorDataSet = trackRecordingService.getSensorData();
|
||||
elevationGain_m = trackRecordingService.getElevationGain_m();
|
||||
}
|
||||
|
||||
setHeartRateSensorData(sensorDataSet);
|
||||
setCadenceSensorData(sensorDataSet);
|
||||
setSpeedSensorData(sensorDataSet, isSelectedTrackRecording());
|
||||
|
||||
setTotalElevationGain(elevationGain_m);
|
||||
}
|
||||
|
||||
private void setHeartRateSensorData(SensorDataSet sensorDataSet) {
|
||||
@@ -464,6 +479,26 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
cadenceValueView.setText(sensorValue);
|
||||
}
|
||||
|
||||
// Set elevation gain
|
||||
private void setTotalElevationGain(Float elevationGain_m) {
|
||||
//TODO Check if we can distribute the total elevation gain via trackStatistics instead of doing some computation in the UI layer.
|
||||
boolean metricUnits = PreferencesUtils.isMetricUnits(getContext());
|
||||
|
||||
Float totalElevationGain = elevationGain_m;
|
||||
|
||||
if (lastTrackStatistics != null && lastTrackStatistics.hasTotalElevationGain()) {
|
||||
if (elevationGain_m == null) {
|
||||
totalElevationGain = lastTrackStatistics.getTotalElevationGain();
|
||||
} else {
|
||||
totalElevationGain += lastTrackStatistics.getTotalElevationGain();
|
||||
}
|
||||
}
|
||||
|
||||
Pair<String, String> parts = StringUtils.formatElevation(getContext(), totalElevationGain, metricUnits);
|
||||
elevationTotalGainValue.setText(parts.first);
|
||||
elevationTotalGainUnit.setText(parts.second);
|
||||
}
|
||||
|
||||
/**
|
||||
* If cadence and hear rate groups are invisible then sensor horizontal line hast to be invisible too.
|
||||
*/
|
||||
@@ -471,7 +506,6 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
if (cadenceGroup.getVisibility() != View.VISIBLE && heartRateGroup.getVisibility() != View.VISIBLE) {
|
||||
sensorHorizontalLine.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setSpeedSensorData(SensorDataSet sensorDataSet, boolean isRecording) {
|
||||
@@ -551,8 +585,9 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
speedMovingUnit.setText(parts.second);
|
||||
}
|
||||
|
||||
// Make elevation visible?
|
||||
// Set elevation (gain)
|
||||
{
|
||||
// Make elevation visible?
|
||||
boolean showElevation = PreferencesUtils.isShowStatsElevation(getContext());
|
||||
elevationGroup.setVisibility(showElevation ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
@@ -593,11 +628,11 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
elevationGroup.setVisibility(showElevation ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (showElevation) {
|
||||
double altitude = lastTrackPoint != null && lastTrackPoint.hasAltitude() ? lastTrackPoint.getAltitude() : Double.NaN;
|
||||
// Current elevation
|
||||
Float altitude = lastTrackPoint != null && lastTrackPoint.hasAltitude() ? (float) lastTrackPoint.getAltitude() : null;
|
||||
Pair<String, String> parts = StringUtils.formatElevation(getContext(), altitude, metricUnits);
|
||||
|
||||
elevationValue.setText(parts.first);
|
||||
elevationUnit.setText(parts.second);
|
||||
elevationCurrentValue.setText(parts.first);
|
||||
elevationCurrentUnit.setText(parts.second);
|
||||
}
|
||||
|
||||
// Set coordinate
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.dennisguse.opentracks.io.file;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
|
||||
public class ExportFile {
|
||||
|
||||
public static DocumentFile getExportDocumentFile(Track.Id trackId, String trackFileFormatExtension, DocumentFile directory, String mimeType) {
|
||||
String fileName = getExportFileNameByTrackId(trackId, trackFileFormatExtension);
|
||||
DocumentFile file = directory.findFile(fileName);
|
||||
if (file == null) {
|
||||
file = directory.createFile(mimeType, fileName);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private static String getExportFileNameByTrackId(Track.Id trackId, String trackFileFormatExtension) {
|
||||
return trackId.getId() + "." + trackFileFormatExtension;
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,9 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
@@ -64,8 +64,8 @@ public class FileTrackExporter implements TrackExporter {
|
||||
try {
|
||||
trackWriter.prepare(outputStream);
|
||||
trackWriter.writeHeader(tracks);
|
||||
for (Track track1 : tracks) {
|
||||
writeWaypoints(track1);
|
||||
for (Track track : tracks) {
|
||||
writeMarkers(track);
|
||||
}
|
||||
boolean hasMultipleTracks = tracks.length > 1;
|
||||
if (hasMultipleTracks) {
|
||||
@@ -89,34 +89,31 @@ public class FileTrackExporter implements TrackExporter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the waypoints.
|
||||
*/
|
||||
private void writeWaypoints(Track track) throws InterruptedException {
|
||||
private void writeMarkers(Track track) throws InterruptedException {
|
||||
/*
|
||||
* TODO: Stream through the waypoints in chunks.
|
||||
* I am leaving the number of waypoints very high which should not be a problem, because we don't try to load them into objects all at the same time.
|
||||
* TODO: Stream through the markers in chunks.
|
||||
* I am leaving the number of markers very high which should not be a problem, because we don't try to load them into objects all at the same time.
|
||||
*/
|
||||
boolean hasWaypoints = false;
|
||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(track.getId(), null, ContentProviderUtils.MAX_LOADED_WAYPOINTS_POINTS)) {
|
||||
boolean hasMarkers = false;
|
||||
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, ContentProviderUtils.MAX_LOADED_MARKERS)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
if (!hasWaypoints) {
|
||||
trackWriter.writeBeginWaypoints(track);
|
||||
hasWaypoints = true;
|
||||
if (!hasMarkers) {
|
||||
trackWriter.writeBeginMarkers(track);
|
||||
hasMarkers = true;
|
||||
}
|
||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursor);
|
||||
trackWriter.writeWaypoint(waypoint);
|
||||
Marker marker = contentProviderUtils.createMarker(cursor);
|
||||
trackWriter.writeMarker(marker);
|
||||
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasWaypoints) {
|
||||
trackWriter.writeEndWaypoints();
|
||||
if (hasMarkers) {
|
||||
trackWriter.writeEndMarkers();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ import java.io.PrintWriter;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -33,7 +33,7 @@ import de.dennisguse.opentracks.util.StringUtils;
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
//TODO Export waypoints
|
||||
//TODO Export markers
|
||||
public class GpxTrackWriter implements TrackWriter {
|
||||
|
||||
private static final NumberFormat ELEVATION_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||
@@ -120,27 +120,27 @@ public class GpxTrackWriter implements TrackWriter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBeginWaypoints(Track track) {
|
||||
public void writeBeginMarkers(Track track) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndWaypoints() {
|
||||
public void writeEndMarkers() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeWaypoint(Waypoint waypoint) {
|
||||
public void writeMarker(Marker marker) {
|
||||
if (printWriter != null) {
|
||||
Location location = waypoint.getLocation();
|
||||
Location location = marker.getLocation();
|
||||
printWriter.println("<wpt " + formatLocation(location) + ">");
|
||||
if (location.hasAltitude()) {
|
||||
printWriter.println("<ele>" + ELEVATION_FORMAT.format(location.getAltitude()) + "</ele>");
|
||||
}
|
||||
printWriter.println("<time>" + StringUtils.formatDateTimeIso8601(location.getTime()) + "</time>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(waypoint.getName()) + "</name>");
|
||||
printWriter.println("<desc>" + StringUtils.formatCData(waypoint.getDescription()) + "</desc>");
|
||||
printWriter.println("<type>" + StringUtils.formatCData(waypoint.getCategory()) + "</type>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(marker.getName()) + "</name>");
|
||||
printWriter.println("<desc>" + StringUtils.formatCData(marker.getDescription()) + "</desc>");
|
||||
printWriter.println("<type>" + StringUtils.formatCData(marker.getCategory()) + "</type>");
|
||||
printWriter.println("</wpt>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.DescriptionGenerator;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
@@ -40,7 +40,7 @@ import de.dennisguse.opentracks.util.StringUtils;
|
||||
*/
|
||||
public class KmlTrackWriter implements TrackWriter {
|
||||
|
||||
public static final String WAYPOINT_STYLE = "waypoint";
|
||||
public static final String MARKER_STYLE = "waypoint";
|
||||
private static final String START_STYLE = "start";
|
||||
private static final String END_STYLE = "end";
|
||||
private static final String TRACK_STYLE = "track";
|
||||
@@ -50,8 +50,9 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
public static final String EXTENDED_DATA_TYPE_CADENCE = "cadence";
|
||||
public static final String EXTENDED_DATA_TYPE_HEART_RATE = "heart_rate";
|
||||
public static final String EXTENDED_DATA_TYPE_POWER = "power";
|
||||
public static final String EXTENDED_DATA_TYPE_ELEVATION_GAIN = "elevation_gain";
|
||||
|
||||
private static final String WAYPOINT_ICON = "http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png";
|
||||
private static final String MARKER_ICON = "http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png";
|
||||
private static final String START_ICON = "http://maps.google.com/mapfiles/kml/paddle/grn-circle.png";
|
||||
private static final String END_ICON = "http://maps.google.com/mapfiles/kml/paddle/red-circle.png";
|
||||
private static final String TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png";
|
||||
@@ -68,12 +69,13 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
private final List<Float> powerList = new ArrayList<>();
|
||||
private final List<Float> cadenceList = new ArrayList<>();
|
||||
private final List<Float> heartRateList = new ArrayList<>();
|
||||
private final List<Float> elevationGainList = new ArrayList<>();
|
||||
|
||||
private TrackPoint startTrackPoint;
|
||||
|
||||
/**
|
||||
* @param context the context
|
||||
* @param exportTrackDetail should detailed information about the track be exported (e.g., title, description, waypoints, timing)?
|
||||
* @param exportTrackDetail should detailed information about the track be exported (e.g., title, description, markers, timing)?
|
||||
* @param exportSensorData should {@link TrackPoint}'s sensor data be exported?
|
||||
* @param exportPhotos should pictures be exported (if true: exports to KMZ)?
|
||||
*/
|
||||
@@ -122,7 +124,7 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
writeTrackStyle();
|
||||
writePlacemarkerStyle(START_STYLE, START_ICON, 32, 1);
|
||||
writePlacemarkerStyle(END_STYLE, END_ICON, 32, 1);
|
||||
writePlacemarkerStyle(WAYPOINT_STYLE, WAYPOINT_ICON, 20, 2);
|
||||
writePlacemarkerStyle(MARKER_STYLE, MARKER_ICON, 20, 2);
|
||||
printWriter.println("<Schema id=\"" + SCHEMA_ID + "\">");
|
||||
|
||||
writeSimpleArrayStyle(EXTENDED_DATA_TYPE_SPEED, context.getString(R.string.description_speed_ms));
|
||||
@@ -145,7 +147,7 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBeginWaypoints(Track track) {
|
||||
public void writeBeginMarkers(Track track) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<Folder>");
|
||||
if (exportTrackDetail) {
|
||||
@@ -156,21 +158,21 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndWaypoints() {
|
||||
public void writeEndMarkers() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("</Folder>");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeWaypoint(Waypoint waypoint) {
|
||||
public void writeMarker(Marker marker) {
|
||||
if (printWriter != null && exportTrackDetail) {
|
||||
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, waypoint.getTrackId(), waypoint.getPhotoURI()) != null;
|
||||
if (waypoint.hasPhoto() && exportPhotos && existsPhoto) {
|
||||
float heading = getHeading(waypoint.getTrackId(), waypoint.getLocation());
|
||||
writePhotoOverlay(waypoint, heading);
|
||||
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, marker.getTrackId(), marker.getPhotoURI()) != null;
|
||||
if (marker.hasPhoto() && exportPhotos && existsPhoto) {
|
||||
float heading = getHeading(marker.getTrackId(), marker.getLocation());
|
||||
writePhotoOverlay(marker, heading);
|
||||
} else {
|
||||
writePlacemark(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(), WAYPOINT_STYLE, waypoint.getLocation());
|
||||
writePlacemark(marker.getName(), marker.getCategory(), marker.getDescription(), MARKER_STYLE, marker.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,6 +259,9 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
if (heartRateList.size() > 0) {
|
||||
writeSimpleArrayData(heartRateList, EXTENDED_DATA_TYPE_HEART_RATE);
|
||||
}
|
||||
if (elevationGainList.size() > 0) {
|
||||
writeSimpleArrayData(elevationGainList, EXTENDED_DATA_TYPE_ELEVATION_GAIN);
|
||||
}
|
||||
}
|
||||
printWriter.println("</SchemaData>");
|
||||
printWriter.println("</ExtendedData>");
|
||||
@@ -287,6 +292,9 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
if (trackPoint.hasPower()) {
|
||||
powerList.add(trackPoint.getPower());
|
||||
}
|
||||
if (trackPoint.hasElevationGain()) {
|
||||
elevationGainList.add(trackPoint.getElevationGain());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,30 +337,24 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a photo overlay from waypoint.
|
||||
*
|
||||
* @param waypoint Waypoint object.
|
||||
* @param heading the heading.
|
||||
*/
|
||||
private void writePhotoOverlay(Waypoint waypoint, float heading) {
|
||||
private void writePhotoOverlay(Marker marker, float heading) {
|
||||
if (exportTrackDetail) {
|
||||
printWriter.println("<PhotoOverlay>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(waypoint.getName()) + "</name>");
|
||||
printWriter.println("<description>" + StringUtils.formatCData(waypoint.getDescription()) + "</description>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(marker.getName()) + "</name>");
|
||||
printWriter.println("<description>" + StringUtils.formatCData(marker.getDescription()) + "</description>");
|
||||
printWriter.print("<Camera>");
|
||||
printWriter.print("<longitude>" + waypoint.getLocation().getLongitude() + "</longitude>");
|
||||
printWriter.print("<latitude>" + waypoint.getLocation().getLatitude() + "</latitude>");
|
||||
printWriter.print("<longitude>" + marker.getLocation().getLongitude() + "</longitude>");
|
||||
printWriter.print("<latitude>" + marker.getLocation().getLatitude() + "</latitude>");
|
||||
printWriter.print("<altitude>20</altitude>");
|
||||
printWriter.print("<heading>" + heading + "</heading>");
|
||||
printWriter.print("<tilt>90</tilt>");
|
||||
printWriter.println("</Camera>");
|
||||
printWriter.println("<TimeStamp><when>" + getTime(waypoint.getLocation()) + "</when></TimeStamp>");
|
||||
printWriter.println("<styleUrl>#" + KmlTrackWriter.WAYPOINT_STYLE + "</styleUrl>");
|
||||
writeCategory(waypoint.getCategory());
|
||||
printWriter.println("<TimeStamp><when>" + getTime(marker.getLocation()) + "</when></TimeStamp>");
|
||||
printWriter.println("<styleUrl>#" + KmlTrackWriter.MARKER_STYLE + "</styleUrl>");
|
||||
writeCategory(marker.getCategory());
|
||||
|
||||
if (exportPhotos) {
|
||||
printWriter.println("<Icon><href>" + KmzTrackExporter.buildKmzImageFilePath(waypoint) + "</href></Icon>");
|
||||
printWriter.println("<Icon><href>" + KmzTrackExporter.buildKmzImageFilePath(marker) + "</href></Icon>");
|
||||
}
|
||||
|
||||
printWriter.print("<ViewVolume>");
|
||||
@@ -363,7 +365,7 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
printWriter.print("<topFov>45</topFov>");
|
||||
printWriter.println("</ViewVolume>");
|
||||
printWriter.println("<Point>");
|
||||
printWriter.println("<coordinates>" + getCoordinates(waypoint.getLocation(), ",") + "</coordinates>");
|
||||
printWriter.println("<coordinates>" + getCoordinates(marker.getLocation(), ",") + "</coordinates>");
|
||||
printWriter.println("</Point>");
|
||||
printWriter.println("</PhotoOverlay>");
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ import java.io.OutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
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.util.FileUtils;
|
||||
|
||||
@@ -76,10 +76,7 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||
ZipOutputStream zipOutputStream = null;
|
||||
try {
|
||||
zipOutputStream = new ZipOutputStream(outputStream);
|
||||
|
||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
|
||||
// Add kml file
|
||||
ZipEntry zipEntry = new ZipEntry(KMZ_KML_FILE);
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
@@ -97,31 +94,23 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
} catch (InterruptedException | IOException e) {
|
||||
Log.e(TAG, "Unable to write track", e);
|
||||
return false;
|
||||
} finally {
|
||||
if (zipOutputStream != null) {
|
||||
try {
|
||||
zipOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to close zip input stream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addImages(Context context, Track[] tracks, ZipOutputStream zipOutputStream) throws InterruptedException, IOException {
|
||||
for (Track track : tracks) {
|
||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(track.getId(), null, -1)) {
|
||||
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, -1)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursor);
|
||||
if (waypoint.hasPhoto()) {
|
||||
Uri uriPhoto = waypoint.getPhotoURI();
|
||||
Marker marker = contentProviderUtils.createMarker(cursor);
|
||||
if (marker.hasPhoto()) {
|
||||
Uri uriPhoto = marker.getPhotoURI();
|
||||
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, track.getId(), uriPhoto) != null;
|
||||
if (existsPhoto) {
|
||||
addImage(context, zipOutputStream, uriPhoto, waypoint);
|
||||
addImage(context, zipOutputStream, uriPhoto, marker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,9 +121,9 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void addImage(Context context, ZipOutputStream zipOutputStream, Uri uri, Waypoint waypoint) throws IOException {
|
||||
private void addImage(Context context, ZipOutputStream zipOutputStream, Uri uri, Marker marker) throws IOException {
|
||||
try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) {
|
||||
ZipEntry zipEntry = new ZipEntry(buildKmzImageFilePath(waypoint));
|
||||
ZipEntry zipEntry = new ZipEntry(buildKmzImageFilePath(marker));
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
|
||||
if (inputStream == null) throw new FileNotFoundException();
|
||||
@@ -157,13 +146,11 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the path for the image that will be saved inside KMZ_IMAGES_DIR for the waypoint.
|
||||
*
|
||||
* @param waypoint Waypoint object.
|
||||
* Builds and returns the path for the image that will be saved inside KMZ_IMAGES_DIR for the marker.
|
||||
*/
|
||||
public static String buildKmzImageFilePath(Waypoint waypoint) {
|
||||
String ext = FileUtils.getExtension(waypoint.getPhotoUrl());
|
||||
public static String buildKmzImageFilePath(Marker marker) {
|
||||
String ext = FileUtils.getExtension(marker.getPhotoUrl());
|
||||
ext = ext == null ? "" : "." + ext;
|
||||
return KMZ_IMAGES_DIR + File.separatorChar + FileUtils.sanitizeFileName(waypoint.getId() + ext);
|
||||
return KMZ_IMAGES_DIR + File.separatorChar + FileUtils.sanitizeFileName(marker.getId().getId() + ext);
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,9 @@ package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
|
||||
/**
|
||||
* Interface for writing tracks to a file. The expected sequence of calls is:
|
||||
@@ -28,10 +28,10 @@ import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
* {@link #prepare(OutputStream)}
|
||||
* {@link #writeHeader(Track[])}
|
||||
* For each track:
|
||||
* {@link #writeBeginWaypoints(Track)}
|
||||
* For each waypoint:
|
||||
* {@link #writeWaypoint(Waypoint)}
|
||||
* {@link #writeEndWaypoints()}
|
||||
* {@link #writeBeginMarkers(Track)}
|
||||
* For each marker:
|
||||
* {@link #writeMarker(Marker)}
|
||||
* {@link #writeEndMarkers()}
|
||||
* {@link #writeMultiTrackBegin()}
|
||||
* For each track:
|
||||
* {@link #writeBeginTrack(Track, TrackPoint)}
|
||||
@@ -50,11 +50,6 @@ import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
*/
|
||||
public interface TrackWriter {
|
||||
|
||||
/**
|
||||
* Prepares the output stream.
|
||||
*
|
||||
* @param outputStream the output stream
|
||||
*/
|
||||
void prepare(OutputStream outputStream);
|
||||
|
||||
/**
|
||||
@@ -62,77 +57,27 @@ public interface TrackWriter {
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Writes the header
|
||||
*
|
||||
* @param tracks the tracks
|
||||
*/
|
||||
void writeHeader(Track[] tracks);
|
||||
|
||||
/**
|
||||
* Writes the footer.
|
||||
*/
|
||||
void writeFooter();
|
||||
|
||||
/**
|
||||
* Writes the beginning of the waypoints.
|
||||
*
|
||||
* @param track the track
|
||||
*/
|
||||
void writeBeginWaypoints(Track track);
|
||||
void writeBeginMarkers(Track track);
|
||||
|
||||
/**
|
||||
* Writes the end of the waypoints.
|
||||
*/
|
||||
void writeEndWaypoints();
|
||||
void writeEndMarkers();
|
||||
|
||||
/**
|
||||
* Writes a waypoint.
|
||||
*
|
||||
* @param waypoint the waypoint
|
||||
*/
|
||||
void writeWaypoint(Waypoint waypoint);
|
||||
void writeMarker(Marker marker);
|
||||
|
||||
/**
|
||||
* Writes the beginning of the tracks.
|
||||
*/
|
||||
void writeMultiTrackBegin();
|
||||
|
||||
/**
|
||||
* Writes the end of the tracks,
|
||||
*/
|
||||
void writeMultiTrackEnd();
|
||||
|
||||
/**
|
||||
* Writes the beginning of a track.
|
||||
*
|
||||
* @param track the track
|
||||
* @param startTrackPoint the start location
|
||||
*/
|
||||
void writeBeginTrack(Track track, TrackPoint startTrackPoint);
|
||||
|
||||
/**
|
||||
* Writes the end of a track.
|
||||
*
|
||||
* @param track the track
|
||||
* @param endTrackPoint the end location
|
||||
*/
|
||||
void writeEndTrack(Track track, TrackPoint endTrackPoint);
|
||||
|
||||
/**
|
||||
* Writes open segment.
|
||||
*/
|
||||
void writeOpenSegment();
|
||||
|
||||
/**
|
||||
* Writes close segment.
|
||||
*/
|
||||
void writeCloseSegment();
|
||||
|
||||
/**
|
||||
* Writes a trackPoint.
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
*/
|
||||
void writeTrackPoint(TrackPoint trackPoint);
|
||||
}
|
||||
+34
-37
@@ -39,9 +39,9 @@ import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
@@ -70,7 +70,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
|
||||
private Track.Id importTrackId;
|
||||
private final List<Track.Id> trackIds = new ArrayList<>();
|
||||
private final List<Waypoint> waypoints = new ArrayList<>();
|
||||
private final List<Marker> markers = new ArrayList<>();
|
||||
|
||||
// The current element content
|
||||
//TODO Should be made private and getter be used by child classes.
|
||||
@@ -88,7 +88,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
protected String heartrate;
|
||||
protected String cadence;
|
||||
protected String power;
|
||||
protected String waypointType;
|
||||
protected String markerType;
|
||||
protected String photoUrl;
|
||||
protected String uuid;
|
||||
|
||||
@@ -148,7 +148,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
* On file end.
|
||||
*/
|
||||
protected void onFileEnd() {
|
||||
// Add waypoints to the last imported track
|
||||
// Add markers to the last imported track
|
||||
int size = trackIds.size();
|
||||
if (size == 0) {
|
||||
return;
|
||||
@@ -159,8 +159,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
return;
|
||||
}
|
||||
|
||||
int waypointPosition = -1;
|
||||
Waypoint waypoint = null;
|
||||
int markerPosition = -1;
|
||||
Marker marker = null;
|
||||
TrackPoint trackPoint = null;
|
||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics().getStartTime_ms());
|
||||
// TODO Should not be necessary anymore?
|
||||
@@ -169,18 +169,18 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), -1L, false)) {
|
||||
|
||||
while (true) {
|
||||
if (waypoint == null) {
|
||||
waypointPosition++;
|
||||
waypoint = waypointPosition < waypoints.size() ? waypoints.get(waypointPosition) : null;
|
||||
if (waypoint == null) {
|
||||
// No more waypoints
|
||||
if (marker == null) {
|
||||
markerPosition++;
|
||||
marker = markerPosition < markers.size() ? markers.get(markerPosition) : null;
|
||||
if (marker == null) {
|
||||
// No more markers
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (trackPoint == null) {
|
||||
if (!trackPointIterator.hasNext()) {
|
||||
// No more track points. Ignore the rest of the waypoints.
|
||||
// No more track points. Ignore the rest of the markers.
|
||||
return;
|
||||
}
|
||||
trackPoint = trackPointIterator.next();
|
||||
@@ -188,13 +188,13 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
markerTrackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||
}
|
||||
|
||||
if (waypoint.getLocation().getTime() > trackPoint.getTime()) {
|
||||
if (marker.getLocation().getTime() > trackPoint.getTime()) {
|
||||
trackPoint = null;
|
||||
} else if (waypoint.getLocation().getTime() < trackPoint.getTime()) {
|
||||
Log.w(TAG, "Ignoring waypoint: current trackPoint was after waypoint.");
|
||||
waypoint = null;
|
||||
} else if (marker.getLocation().getTime() < trackPoint.getTime()) {
|
||||
Log.w(TAG, "Ignoring marker: current trackPoint was after marker.");
|
||||
marker = null;
|
||||
} else {
|
||||
// The waypoint trackPoint time matches the track point time
|
||||
// The marker trackPoint time matches the track point time
|
||||
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
||||
// Invalid trackPoint, load the next trackPoint
|
||||
trackPoint = null;
|
||||
@@ -202,19 +202,19 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
}
|
||||
|
||||
// Valid trackPoint
|
||||
if (trackPoint.getLatitude() == waypoint.getLocation().getLatitude() && trackPoint.getLongitude() == waypoint.getLocation().getLongitude()) {
|
||||
String waypointDescription = waypoint.getDescription();
|
||||
String icon = context.getString(R.string.marker_waypoint_icon_url);
|
||||
if (trackPoint.getLatitude() == marker.getLocation().getLatitude() && trackPoint.getLongitude() == marker.getLocation().getLongitude()) {
|
||||
String markerDescription = marker.getDescription();
|
||||
String icon = context.getString(R.string.marker_icon_url);
|
||||
double length = trackStatisticsUpdater.getTrackStatistics().getTotalDistance();
|
||||
long duration = trackStatisticsUpdater.getTrackStatistics().getTotalTime();
|
||||
|
||||
// Insert waypoint
|
||||
Waypoint newWaypoint = new Waypoint(waypoint.getName(), waypointDescription, waypoint.getCategory(), icon, track.getId(), length, duration, trackPoint.getLocation(), waypoint.getPhotoUrl());
|
||||
contentProviderUtils.insertWaypoint(newWaypoint);
|
||||
// Insert marker
|
||||
Marker newMarker = new Marker(marker.getName(), markerDescription, marker.getCategory(), icon, track.getId(), length, duration, trackPoint.getLocation(), marker.getPhotoUrl());
|
||||
contentProviderUtils.insertMarker(newMarker);
|
||||
}
|
||||
|
||||
// Load the next waypoint
|
||||
waypoint = null;
|
||||
// Load the next marker
|
||||
marker = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,7 +231,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
trackId = new Track.Id(Long.parseLong(uri.getLastPathSegment()));
|
||||
} else {
|
||||
if (trackIds.size() > 0) {
|
||||
throw new SAXException(createErrorMessage("Cannot import more than one track to an existing track " + importTrackId));
|
||||
throw new SAXException(createErrorMessage("Cannot import more than one track to an existing track " + importTrackId.getId()));
|
||||
}
|
||||
trackId = importTrackId;
|
||||
contentProviderUtils.clearTrack(trackId);
|
||||
@@ -300,11 +300,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
trackData.lastLocationInCurrentSegment = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a waypoint.
|
||||
*/
|
||||
protected void addWaypoint() throws SAXException {
|
||||
// Waypoint must have a time, else cannot match to the track points
|
||||
protected void addMarker() throws SAXException {
|
||||
// Markers must have a time, else cannot match to the track points
|
||||
if (time == null) {
|
||||
return;
|
||||
}
|
||||
@@ -314,22 +311,22 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
||||
throw new SAXException(createErrorMessage("Invalid location detected: " + trackPoint));
|
||||
}
|
||||
Waypoint waypoint = new Waypoint(trackPoint.getLocation());
|
||||
Marker marker = new Marker(trackPoint.getLocation());
|
||||
|
||||
if (name != null) {
|
||||
waypoint.setName(name);
|
||||
marker.setName(name);
|
||||
}
|
||||
if (description != null) {
|
||||
waypoint.setDescription(description);
|
||||
marker.setDescription(description);
|
||||
}
|
||||
if (category != null) {
|
||||
waypoint.setCategory(category);
|
||||
marker.setCategory(category);
|
||||
}
|
||||
|
||||
if (photoUrl != null) {
|
||||
waypoint.setPhotoUrl(photoUrl);
|
||||
marker.setPhotoUrl(photoUrl);
|
||||
}
|
||||
waypoints.add(waypoint);
|
||||
markers.add(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+15
-5
@@ -21,7 +21,7 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
configureDirectoryChooserIntent(intent);
|
||||
|
||||
startActivityForResult(intent, DIRECTORY_PICKER_REQUEST_CODE);
|
||||
}
|
||||
@@ -33,19 +33,23 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri directoryUri = resultData.getData();
|
||||
|
||||
startActivity(createIntent(directoryUri));
|
||||
startActivity(createNextActivityIntent(directoryUri));
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Intent createIntent(Uri directoryUri);
|
||||
protected void configureDirectoryChooserIntent(Intent intent) {
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
}
|
||||
|
||||
protected abstract Intent createNextActivityIntent(Uri directoryUri);
|
||||
|
||||
|
||||
public static class ImportDirectoryChooserActivity extends DirectoryChooserActivity {
|
||||
|
||||
@Override
|
||||
protected Intent createIntent(Uri directoryUri) {
|
||||
protected Intent createNextActivityIntent(Uri directoryUri) {
|
||||
Intent intent = IntentUtils.newIntent(this, ImportActivity.class);
|
||||
intent.putExtra(ImportActivity.EXTRA_DIRECTORY_URI_KEY, directoryUri);
|
||||
return intent;
|
||||
@@ -55,11 +59,17 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
public static class ExportDirectoryChooserActivity extends DirectoryChooserActivity {
|
||||
|
||||
@Override
|
||||
protected Intent createIntent(Uri directoryUri) {
|
||||
protected Intent createNextActivityIntent(Uri directoryUri) {
|
||||
Intent intent = IntentUtils.newIntent(this, ExportActivity.class);
|
||||
intent.putExtra(ExportActivity.EXTRA_DIRECTORY_URI_KEY, directoryUri);
|
||||
intent.putExtra(ExportActivity.EXTRA_TRACKFILEFORMAT_KEY, PreferencesUtils.getExportTrackFileFormat(this));
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureDirectoryChooserIntent(Intent intent) {
|
||||
super.configureDirectoryChooserIntent(intent);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
private static final String TAG_TRACK_POINT = "trkpt";
|
||||
private static final String TAG_TRACK_SEGMENT = "trkseg";
|
||||
private static final String TAG_TYPE = "type";
|
||||
private static final String TAG_WAYPOINT = "wpt";
|
||||
private static final String TAG_MARKER = "wpt";
|
||||
private static final String TAG_ID = "opentracks:trackid";
|
||||
|
||||
private static final String ATTRIBUTE_LAT = "lat";
|
||||
@@ -71,8 +71,8 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String tag, Attributes attributes) throws SAXException {
|
||||
switch (tag) {
|
||||
case TAG_WAYPOINT:
|
||||
onWaypointStart(attributes);
|
||||
case TAG_MARKER:
|
||||
onMarkerStart(attributes);
|
||||
break;
|
||||
case TAG_TRACK:
|
||||
onTrackStart();
|
||||
@@ -92,8 +92,8 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
case TAG_GPX:
|
||||
onFileEnd();
|
||||
break;
|
||||
case TAG_WAYPOINT:
|
||||
onWaypointEnd();
|
||||
case TAG_MARKER:
|
||||
onMarkerEnd();
|
||||
break;
|
||||
case TAG_TRACK:
|
||||
onTrackEnd();
|
||||
@@ -128,7 +128,7 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
break;
|
||||
case TAG_COMMENT:
|
||||
if (content != null) {
|
||||
waypointType = content.trim();
|
||||
markerType = content.trim();
|
||||
}
|
||||
break;
|
||||
case TAG_EXTENSION_SPEED:
|
||||
@@ -187,12 +187,7 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
insertTrackPoint(trackPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* On waypoint start.
|
||||
*
|
||||
* @param attributes the attributes
|
||||
*/
|
||||
private void onWaypointStart(Attributes attributes) {
|
||||
private void onMarkerStart(Attributes attributes) {
|
||||
name = null;
|
||||
description = null;
|
||||
category = null;
|
||||
@@ -201,13 +196,10 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
longitude = attributes.getValue(ATTRIBUTE_LON);
|
||||
altitude = null;
|
||||
time = null;
|
||||
waypointType = null;
|
||||
markerType = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* On waypoint end.
|
||||
*/
|
||||
private void onWaypointEnd() throws SAXException {
|
||||
addWaypoint();
|
||||
private void onMarkerEnd() throws SAXException {
|
||||
addMarker();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
|
||||
private static final String TAG = KmlFileTrackImporter.class.getSimpleName();
|
||||
|
||||
private static final String WAYPOINT_STYLE = "#" + KmlTrackWriter.WAYPOINT_STYLE;
|
||||
private static final String MARKER_STYLE = "#" + KmlTrackWriter.MARKER_STYLE;
|
||||
|
||||
private static final String TAG_COORDINATES = "coordinates";
|
||||
private static final String TAG_DESCRIPTION = "description";
|
||||
@@ -63,11 +63,12 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
|
||||
private boolean trackStarted = false;
|
||||
private String extendedDataType;
|
||||
private ArrayList<TrackPoint> trackPoints;
|
||||
private ArrayList<Float> speedList;
|
||||
private ArrayList<Float> cadenceList;
|
||||
private ArrayList<Float> heartRateList;
|
||||
private ArrayList<Float> powerList;
|
||||
private ArrayList<TrackPoint> trackPoints = new ArrayList<>();
|
||||
private ArrayList<Float> speedList = new ArrayList<>();
|
||||
private ArrayList<Float> cadenceList = new ArrayList<>();
|
||||
private ArrayList<Float> heartRateList = new ArrayList<>();
|
||||
private ArrayList<Float> powerList = new ArrayList<>();
|
||||
private ArrayList<Float> elevationGainList = new ArrayList<>();
|
||||
|
||||
public KmlFileTrackImporter(Context context) {
|
||||
this(context, new ContentProviderUtils(context));
|
||||
@@ -83,8 +84,8 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
switch (tag) {
|
||||
case TAG_PLACEMARK:
|
||||
case TAG_PHOTO_OVERLAY:
|
||||
// Note that a track is contained in a Placemark, calling onWaypointStart will clear various track variables like name, category, and description.
|
||||
onWaypointStart();
|
||||
// Note that a track is contained in a Placemark, calling onMarkerStart will clear various track variables like name, category, and description.
|
||||
onMarkerStart();
|
||||
break;
|
||||
case TAG_GX_MULTI_TRACK:
|
||||
trackStarted = true;
|
||||
@@ -110,11 +111,11 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
break;
|
||||
case TAG_PLACEMARK:
|
||||
case TAG_PHOTO_OVERLAY:
|
||||
// Note that a track is contained in a Placemark, calling onWaypointend is save since waypointType is not set for a track.
|
||||
onWaypointEnd();
|
||||
// Note that a track is contained in a Placemark, calling onMarkerEnd is save since markerType is not set for a track.
|
||||
onMarkerEnd();
|
||||
break;
|
||||
case TAG_COORDINATES:
|
||||
onWaypointLocationEnd();
|
||||
onMarkerLocationEnd();
|
||||
break;
|
||||
case TAG_GX_MULTI_TRACK:
|
||||
onTrackEnd();
|
||||
@@ -160,7 +161,7 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
break;
|
||||
case TAG_STYLE_URL:
|
||||
if (content != null) {
|
||||
waypointType = content.trim();
|
||||
markerType = content.trim();
|
||||
}
|
||||
break;
|
||||
case TAG_HREF:
|
||||
@@ -174,10 +175,7 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
content = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* On waypoint start.
|
||||
*/
|
||||
private void onWaypointStart() {
|
||||
private void onMarkerStart() {
|
||||
// Reset all Placemark variables
|
||||
name = null;
|
||||
icon = null;
|
||||
@@ -188,27 +186,21 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
longitude = null;
|
||||
altitude = null;
|
||||
time = null;
|
||||
waypointType = null;
|
||||
markerType = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* On waypoint end.
|
||||
*/
|
||||
private void onWaypointEnd() throws SAXException {
|
||||
if (!WAYPOINT_STYLE.equals(waypointType)) {
|
||||
private void onMarkerEnd() throws SAXException {
|
||||
if (!MARKER_STYLE.equals(markerType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is photoUrl it has to be changed because that url in kml file is a relative path to the internal kmz file.
|
||||
photoUrl = getInternalPhotoUrl(photoUrl);
|
||||
|
||||
addWaypoint();
|
||||
addMarker();
|
||||
}
|
||||
|
||||
/**
|
||||
* On waypoint location end.
|
||||
*/
|
||||
private void onWaypointLocationEnd() {
|
||||
private void onMarkerLocationEnd() {
|
||||
if (content != null) {
|
||||
String[] parts = content.trim().split(",");
|
||||
if (parts.length != 2 && parts.length != 3) {
|
||||
@@ -223,11 +215,12 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
@Override
|
||||
protected void onTrackSegmentStart() {
|
||||
super.onTrackSegmentStart();
|
||||
trackPoints = new ArrayList<>();
|
||||
speedList = new ArrayList<>();
|
||||
heartRateList = new ArrayList<>();
|
||||
cadenceList = new ArrayList<>();
|
||||
powerList = new ArrayList<>();
|
||||
trackPoints.clear();
|
||||
speedList.clear();
|
||||
heartRateList.clear();
|
||||
cadenceList.clear();
|
||||
powerList.clear();
|
||||
elevationGainList.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,6 +243,9 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
if (i < powerList.size()) {
|
||||
trackPoint.setPower(powerList.get(i));
|
||||
}
|
||||
if (i < elevationGainList.size()) {
|
||||
trackPoint.setElevationGain(elevationGainList.get(i));
|
||||
}
|
||||
|
||||
insertTrackPoint(trackPoint);
|
||||
}
|
||||
@@ -316,6 +312,9 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_CADENCE:
|
||||
cadenceList.add(value);
|
||||
break;
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_ELEVATION_GAIN:
|
||||
elevationGainList.add(value);
|
||||
break;
|
||||
default:
|
||||
Log.w(TAG, "Data from extended data " + extendedDataType + " is not (yet) supported.");
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
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.io.file.exporter.KmzTrackExporter;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
@@ -191,20 +191,20 @@ public class KmzTrackImporter implements TrackImporter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all images that remained in external storage that doesn't have waypoint (marker) associated.
|
||||
* Deletes all images that remained in external storage that doesn't have a marker associated.
|
||||
*
|
||||
* @param context the Context object.
|
||||
* @param trackId the id of the Track.
|
||||
*/
|
||||
private void deleteOrphanImages(Context context, Track.Id trackId) {
|
||||
if (!trackId.isValid()) {
|
||||
// 1.- Gets all photo names in the waypoints of the track identified by id.
|
||||
// 1.- Gets all photo names in the markers of the track identified by id.
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||
List<Waypoint> waypoints = contentProviderUtils.getWaypoints(trackId);
|
||||
List<Marker> markers = contentProviderUtils.getMarkers(trackId);
|
||||
List<String> photosName = new ArrayList<>();
|
||||
for (Waypoint w : waypoints) {
|
||||
if (w.hasPhoto()) {
|
||||
String photoUrl = Uri.decode(w.getPhotoUrl());
|
||||
for (Marker marker : markers) {
|
||||
if (marker.hasPhoto()) {
|
||||
String photoUrl = Uri.decode(marker.getPhotoUrl());
|
||||
photosName.add(photoUrl.substring(photoUrl.lastIndexOf(File.separatorChar) + 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ import java.util.List;
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.TrackListActivity;
|
||||
import de.dennisguse.opentracks.TrackRecordingActivity;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
@@ -49,6 +49,7 @@ import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||
import de.dennisguse.opentracks.services.handlers.HandlerServer;
|
||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||
import de.dennisguse.opentracks.services.sensors.ElevationSumManager;
|
||||
import de.dennisguse.opentracks.services.tasks.AnnouncementPeriodicTaskFactory;
|
||||
import de.dennisguse.opentracks.services.tasks.PeriodicTaskExecutor;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
@@ -115,6 +116,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
// The following variables are set when recording:
|
||||
private WakeLock wakeLock;
|
||||
private BluetoothRemoteSensorManager remoteSensorManager;
|
||||
private ElevationSumManager elevationSumManager;
|
||||
|
||||
private TrackStatisticsUpdater trackStatisticsUpdater;
|
||||
private TrackPoint lastTrackPoint;
|
||||
@@ -174,6 +176,11 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
remoteSensorManager = null;
|
||||
}
|
||||
|
||||
if (elevationSumManager != null) {
|
||||
elevationSumManager.stop(this);
|
||||
elevationSumManager = null;
|
||||
}
|
||||
|
||||
// Reverse order from onCreate
|
||||
showNotification(false); //TODO Why?
|
||||
|
||||
@@ -215,6 +222,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
return trackStatisticsUpdater.getTrackStatistics();
|
||||
}
|
||||
|
||||
//TODO Throw exception, when not recording.
|
||||
public long getTotalTime() {
|
||||
if (trackStatisticsUpdater == null) {
|
||||
return 0;
|
||||
@@ -225,43 +233,38 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
return trackStatisticsUpdater.getTrackStatistics().getTotalTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a waypoint.
|
||||
*
|
||||
* @return the waypoint id
|
||||
*/
|
||||
public Waypoint.Id insertWaypoint(String name, String category, String description, String photoUrl) {
|
||||
public Marker.Id insertMarker(String name, String category, String description, String photoUrl) {
|
||||
if (!isRecording() || isPaused()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (name == null) {
|
||||
int nextWaypointNumber = contentProviderUtils.getNextWaypointNumber(recordingTrackId);
|
||||
if (nextWaypointNumber == -1) {
|
||||
nextWaypointNumber = 1;
|
||||
int nextMarkerNumber = contentProviderUtils.getNextMarkerNumber(recordingTrackId);
|
||||
if (nextMarkerNumber == -1) {
|
||||
nextMarkerNumber = 1;
|
||||
}
|
||||
name = getString(R.string.marker_name_format, nextWaypointNumber + 1);
|
||||
name = getString(R.string.marker_name_format, nextMarkerNumber + 1);
|
||||
}
|
||||
|
||||
TrackPoint trackPoint = getLastValidTrackPointInCurrentSegment(recordingTrackId);
|
||||
if (trackPoint == null) {
|
||||
Log.i(TAG, "Could not create a waypoint as trackPoint is unknown.");
|
||||
Log.i(TAG, "Could not create a marker as trackPoint is unknown.");
|
||||
return null;
|
||||
}
|
||||
|
||||
category = category != null ? category : "";
|
||||
description = description != null ? description : "";
|
||||
String icon = getString(R.string.marker_waypoint_icon_url);
|
||||
String icon = getString(R.string.marker_icon_url);
|
||||
photoUrl = photoUrl != null ? photoUrl : "";
|
||||
|
||||
TrackStatistics stats = trackStatisticsUpdater.getTrackStatistics();
|
||||
double length = stats.getTotalDistance();
|
||||
long duration = stats.getTotalTime();
|
||||
|
||||
// Insert waypoint
|
||||
Waypoint waypoint = new Waypoint(name, description, category, icon, recordingTrackId, length, duration, trackPoint.getLocation(), photoUrl);
|
||||
Uri uri = contentProviderUtils.insertWaypoint(waypoint);
|
||||
return new Waypoint.Id(ContentUris.parseId(uri));
|
||||
// Insert marker
|
||||
Marker marker = new Marker(name, description, category, icon, recordingTrackId, length, duration, trackPoint.getLocation(), photoUrl);
|
||||
Uri uri = contentProviderUtils.insertMarker(marker);
|
||||
return new Marker.Id(ContentUris.parseId(uri));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,7 +311,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
void resumeTrack(Track.Id trackId) {
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
Log.e(TAG, "Ignore resumeTrack. Track " + trackId + " does not exists.");
|
||||
Log.e(TAG, "Ignore resumeTrack. Track " + trackId.getId() + " does not exists.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -332,7 +335,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
Track track = contentProviderUtils.getTrack(recordingTrackId);
|
||||
if (track == null) {
|
||||
if (isRecording()) {
|
||||
Log.w(TAG, "track is null, but recordingTrackId not -1L. " + recordingTrackId);
|
||||
Log.w(TAG, "track is null, but recordingTrackId not -1L. " + recordingTrackId.getId());
|
||||
updateRecordingState(null, true);
|
||||
}
|
||||
showNotification(false);
|
||||
@@ -375,6 +378,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
// Update instance variables
|
||||
remoteSensorManager = new BluetoothRemoteSensorManager(this);
|
||||
remoteSensorManager.start();
|
||||
|
||||
elevationSumManager = new ElevationSumManager();
|
||||
elevationSumManager.start(this);
|
||||
|
||||
lastTrackPoint = null;
|
||||
isIdle = false;
|
||||
|
||||
@@ -460,6 +467,11 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
remoteSensorManager.stop();
|
||||
remoteSensorManager = null;
|
||||
}
|
||||
if (elevationSumManager != null) {
|
||||
elevationSumManager.stop(this);
|
||||
elevationSumManager = null;
|
||||
}
|
||||
|
||||
lastTrackPoint = null;
|
||||
|
||||
handlerServer.stop(this);
|
||||
@@ -560,15 +572,17 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
insertTrackPoint(track, TrackPoint.createPause());
|
||||
|
||||
insertTrackPoint(track, trackPoint);
|
||||
isIdle = false;
|
||||
|
||||
isIdle = false;
|
||||
lastTrackPoint = trackPoint;
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackPoint.hasSensorData() || distanceToLastTrackLocation >= recordingDistanceInterval) {
|
||||
insertTrackPointIfNewer(track, lastTrackPoint);
|
||||
|
||||
insertTrackPoint(track, trackPoint);
|
||||
|
||||
isIdle = false;
|
||||
|
||||
lastTrackPoint = trackPoint;
|
||||
@@ -577,7 +591,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
|
||||
if (!isIdle && !TrackPointUtils.isMoving(trackPoint)) {
|
||||
insertTrackPointIfNewer(track, lastTrackPoint);
|
||||
|
||||
insertTrackPoint(track, trackPoint);
|
||||
|
||||
isIdle = true;
|
||||
|
||||
lastTrackPoint = trackPoint;
|
||||
@@ -586,7 +602,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
|
||||
if (isIdle && TrackPointUtils.isMoving(trackPoint)) {
|
||||
insertTrackPointIfNewer(track, lastTrackPoint);
|
||||
|
||||
insertTrackPoint(track, trackPoint);
|
||||
|
||||
isIdle = false;
|
||||
|
||||
lastTrackPoint = trackPoint;
|
||||
@@ -636,6 +654,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
*/
|
||||
private void insertTrackPoint(@NonNull Track track, @NonNull TrackPoint trackPoint) {
|
||||
try {
|
||||
if (elevationSumManager != null) {
|
||||
trackPoint.setElevationGain(elevationSumManager.getElevationGain_m());
|
||||
elevationSumManager.reset();
|
||||
}
|
||||
contentProviderUtils.insertTrackPoint(trackPoint, track.getId());
|
||||
trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||
updateTrackTotalTime(track);
|
||||
@@ -676,6 +698,17 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative elevation gain (since last trackpoint).
|
||||
*/
|
||||
Float getElevationGain_m() {
|
||||
if (elevationSumManager == null || !elevationSumManager.isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return elevationSumManager.getElevationGain_m();
|
||||
}
|
||||
|
||||
private void showNotification(boolean isGpsStarted) {
|
||||
if (isRecording()) {
|
||||
Intent intent = IntentUtils.newIntent(this, TrackRecordingActivity.class)
|
||||
|
||||
@@ -2,9 +2,9 @@ package de.dennisguse.opentracks.services;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||
@@ -90,8 +90,8 @@ class TrackRecordingServiceBinder extends android.os.Binder implements TrackReco
|
||||
}
|
||||
|
||||
@Override
|
||||
public Waypoint.Id insertWaypoint(String name, String category, String description, String photoUrl) {
|
||||
return trackRecordingService.insertWaypoint(name, category, description, photoUrl);
|
||||
public Marker.Id insertMarker(String name, String category, String description, String photoUrl) {
|
||||
return trackRecordingService.insertMarker(name, category, description, photoUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -99,6 +99,11 @@ class TrackRecordingServiceBinder extends android.os.Binder implements TrackReco
|
||||
return trackRecordingService.getSensorDataSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getElevationGain_m() {
|
||||
return trackRecordingService.getElevationGain_m();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
public void setRemoteSensorManager(BluetoothRemoteSensorManager remoteSensorManager) {
|
||||
|
||||
+5
-11
@@ -31,8 +31,8 @@ import androidx.annotation.NonNull;
|
||||
import de.dennisguse.opentracks.BuildConfig;
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.TrackEditActivity;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
@@ -181,16 +181,16 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
|
||||
*
|
||||
* @return the id of the marker or null if none could be created.
|
||||
*/
|
||||
public Waypoint.Id addMarker(Context context, String name, String category, String description, String photoUrl) {
|
||||
public Marker.Id addMarker(Context context, String name, String category, String description, String photoUrl) {
|
||||
TrackRecordingServiceInterface trackRecordingService = getServiceIfBound();
|
||||
if (trackRecordingService == null) {
|
||||
Log.d(TAG, "Unable to add marker, no track recording service");
|
||||
} else {
|
||||
try {
|
||||
Waypoint.Id waypoint = trackRecordingService.insertWaypoint(name, category, description, photoUrl);
|
||||
if (waypoint != null) {
|
||||
Marker.Id marker = trackRecordingService.insertMarker(name, category, description, photoUrl);
|
||||
if (marker != null) {
|
||||
Toast.makeText(context, R.string.marker_add_success, Toast.LENGTH_SHORT).show();
|
||||
return waypoint;
|
||||
return marker;
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Unable to add marker.", e);
|
||||
@@ -201,12 +201,6 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the recording.
|
||||
*
|
||||
* @param context the context
|
||||
* @param showEditor true to show the editor
|
||||
*/
|
||||
public void stopRecording(@NonNull Context context, boolean showEditor) {
|
||||
TrackRecordingServiceInterface trackRecordingService = getServiceIfBound();
|
||||
if (trackRecordingService == null) {
|
||||
|
||||
+13
-37
@@ -17,9 +17,9 @@ package de.dennisguse.opentracks.services;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||
@@ -30,46 +30,20 @@ import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||
*/
|
||||
public interface TrackRecordingServiceInterface {
|
||||
|
||||
/**
|
||||
* Starts gps.
|
||||
*/
|
||||
void startGps();
|
||||
|
||||
/**
|
||||
* Stops gps.
|
||||
*/
|
||||
void stopGps();
|
||||
|
||||
/**
|
||||
* Starts recording a new track.
|
||||
*
|
||||
* @return the track ID of the new track.
|
||||
*/
|
||||
Track.Id startNewTrack();
|
||||
|
||||
/**
|
||||
* Resumes the track identified by trackId.
|
||||
*/
|
||||
void resumeTrack(Track.Id trackId);
|
||||
|
||||
/**
|
||||
* Pauses the current recording track.
|
||||
*/
|
||||
void pauseCurrentTrack();
|
||||
|
||||
/**
|
||||
* Resumes the current recording track.
|
||||
*/
|
||||
void resumeCurrentTrack();
|
||||
|
||||
/**
|
||||
* Ends the current recording track.
|
||||
*/
|
||||
void resumeTrack(Track.Id trackId);
|
||||
|
||||
void endCurrentTrack();
|
||||
|
||||
/**
|
||||
* Returns true if currently recording a track.
|
||||
*/
|
||||
boolean isRecording();
|
||||
|
||||
/**
|
||||
@@ -88,20 +62,22 @@ public interface TrackRecordingServiceInterface {
|
||||
//TODO milliseconds?
|
||||
long getTotalTime();
|
||||
|
||||
/**
|
||||
* Inserts a waypoint in the current recording track.
|
||||
*
|
||||
* @return the ID of the inserted waypoint
|
||||
*/
|
||||
Waypoint.Id insertWaypoint(String name, String category, String description, String photoUrl);
|
||||
Marker.Id insertMarker(String name, String category, String description, String photoUrl);
|
||||
|
||||
/**
|
||||
* Gets the current sensor data. Returns null if there is no data.
|
||||
* Gets the current sensor data.
|
||||
*
|
||||
* @return SensorDataSet object.
|
||||
* @return SensorDataSet object or null.
|
||||
*/
|
||||
SensorDataSet getSensorData();
|
||||
|
||||
/**
|
||||
* Gets the current elevation gain.
|
||||
*
|
||||
* @return elevation gain in m or null.
|
||||
*/
|
||||
Float getElevationGain_m();
|
||||
|
||||
@VisibleForTesting
|
||||
void setRemoteSensorManager(BluetoothRemoteSensorManager remoteSensorManager);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user