forked from upstream-mirrors/OpenTracks
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 80dbbbc1ed | |||
| 81e8872a11 | |||
| 4220c62ac0 | |||
| 4b73567075 | |||
| fdff0d255a | |||
| e956cf14c4 | |||
| a1646e1b76 | |||
| 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 | |||
| 3ee7d4504c | |||
| 579509aad8 | |||
| 24ff73ab06 | |||
| 60d5e7e515 | |||
| c610758ae1 | |||
| 17d2755844 | |||
| 0ab14e0f3d | |||
| bcbaf4985a | |||
| b2e8713db0 | |||
| af60e1fdfb | |||
| 75043325ff | |||
| 337e5b9e4d | |||
| 1ff986f1e6 | |||
| 6412bb9fcd | |||
| 8425997c29 | |||
| f4b585b830 | |||
| 47c259fa9a | |||
| 80208e3188 | |||
| 2655d3e773 |
@@ -1,5 +1,13 @@
|
|||||||
# Thanks for your contribution.
|
# 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**
|
**Describe the pull request**
|
||||||
A clear and concise description of what the pull request changes/adds.
|
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"
|
||||||
@@ -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.
|
||||||
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"
|
||||||
+13
-9
@@ -37,6 +37,8 @@ def getVersionName = { ->
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
@@ -45,8 +47,8 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "de.dennisguse.opentracks"
|
applicationId "de.dennisguse.opentracks"
|
||||||
versionCode 3522
|
versionCode 3584
|
||||||
versionName "v3.9.0"
|
versionName "v3.9.5"
|
||||||
|
|
||||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||||
|
|
||||||
@@ -80,15 +82,17 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
|
||||||
|
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
implementation 'androidx.documentfile:documentfile:1.0.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:1.1.3'
|
implementation 'com.android.support.constraint:constraint-layout:2.0.1'
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test:core:1.2.0'
|
androidTestImplementation 'androidx.test:core:1.3.0'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
androidTestImplementation 'androidx.test:rules:1.3.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
androidTestImplementation 'androidx.test:runner:1.3.0'
|
||||||
androidTestImplementation 'org.mockito:mockito-android:3.4.6'
|
androidTestImplementation 'org.mockito:mockito-android:3.5.10'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
v3.9.1: OpenTracks
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- GPS pre-start shows status of fix
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
v3.9.2: OpenTracks
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Fixed force close on API<25 (due to an animation)
|
||||||
|
- Reset recording state (on app startup) if crashed while recording
|
||||||
@@ -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)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
(tbd): OpenTracks
|
(versionName): OpenTracks
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
-
|
-
|
||||||
|
|||||||
@@ -19,13 +19,16 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
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}.
|
* Tests {@link ChartValueSeries}.
|
||||||
*
|
*
|
||||||
@@ -60,16 +63,16 @@ public class ChartValueSeriesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitialConditions() {
|
public void testInitialConditions() {
|
||||||
Assert.assertEquals(1, series.getInterval());
|
assertEquals(1, series.getInterval());
|
||||||
Assert.assertEquals(0, series.getMinMarkerValue());
|
assertEquals(0, series.getMinMarkerValue());
|
||||||
Assert.assertEquals(5, series.getMaxMarkerValue());
|
assertEquals(5, series.getMaxMarkerValue());
|
||||||
Assert.assertTrue(series.isEnabled());
|
assertTrue(series.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEnabled() {
|
public void testEnabled() {
|
||||||
series.setEnabled(false);
|
series.setEnabled(false);
|
||||||
Assert.assertFalse(series.isEnabled());
|
assertFalse(series.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -77,9 +80,9 @@ public class ChartValueSeriesTest {
|
|||||||
series.update(new ChartPoint(0));
|
series.update(new ChartPoint(0));
|
||||||
series.update(new ChartPoint(10));
|
series.update(new ChartPoint(10));
|
||||||
series.updateDimension();
|
series.updateDimension();
|
||||||
Assert.assertEquals(100, series.getInterval());
|
assertEquals(100, series.getInterval());
|
||||||
Assert.assertEquals(0, series.getMinMarkerValue());
|
assertEquals(0, series.getMinMarkerValue());
|
||||||
Assert.assertEquals(500, series.getMaxMarkerValue());
|
assertEquals(500, series.getMaxMarkerValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,9 +90,9 @@ public class ChartValueSeriesTest {
|
|||||||
series.update(new ChartPoint(0));
|
series.update(new ChartPoint(0));
|
||||||
series.update(new ChartPoint(901));
|
series.update(new ChartPoint(901));
|
||||||
series.updateDimension();
|
series.updateDimension();
|
||||||
Assert.assertEquals(1000, series.getInterval());
|
assertEquals(1000, series.getInterval());
|
||||||
Assert.assertEquals(0, series.getMinMarkerValue());
|
assertEquals(0, series.getMinMarkerValue());
|
||||||
Assert.assertEquals(5000, series.getMaxMarkerValue());
|
assertEquals(5000, series.getMaxMarkerValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -97,8 +100,8 @@ public class ChartValueSeriesTest {
|
|||||||
series.update(new ChartPoint(220));
|
series.update(new ChartPoint(220));
|
||||||
series.update(new ChartPoint(250));
|
series.update(new ChartPoint(250));
|
||||||
series.updateDimension();
|
series.updateDimension();
|
||||||
Assert.assertEquals(100, series.getInterval());
|
assertEquals(100, series.getInterval());
|
||||||
Assert.assertEquals(200, series.getMinMarkerValue());
|
assertEquals(200, series.getMinMarkerValue());
|
||||||
Assert.assertEquals(700, series.getMaxMarkerValue());
|
assertEquals(700, series.getMaxMarkerValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import android.content.Context;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
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.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link DescriptionGenerator}.
|
* Tests for {@link DescriptionGenerator}.
|
||||||
*
|
*
|
||||||
@@ -85,7 +86,7 @@ public class DescriptionGeneratorTest {
|
|||||||
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
||||||
|
|
||||||
Assert.assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -119,7 +120,7 @@ public class DescriptionGeneratorTest {
|
|||||||
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<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() {
|
public void testWriteDistance() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
descriptionGenerator.writeDistance(1100, builder, R.string.description_total_distance, "<br>");
|
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() {
|
public void testWriteTime() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
descriptionGenerator.writeTime(1000, builder, R.string.description_total_time, "<br>");
|
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() {
|
public void testWriteSpeed() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
descriptionGenerator.writeSpeed(1.1, builder, R.string.description_average_speed, "\n");
|
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() {
|
public void testWriteElevation() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
descriptionGenerator.writeElevation(4.2, builder, R.string.description_min_elevation, "<br>");
|
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() {
|
public void testWritePace() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
descriptionGenerator.writePace(1.1, builder, R.string.description_average_pace_in_minute, "\n");
|
descriptionGenerator.writePace(1.1, builder, R.string.description_average_pace_in_minute, "\n");
|
||||||
Assert.assertEquals("Average pace: 15:09 min/km (24:23 min/mi)\n", builder.toString());
|
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 androidx.test.rule.provider.ProviderTestRule;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
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.ScoredResult;
|
||||||
import de.dennisguse.opentracks.content.SearchEngine.SearchQuery;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
||||||
import de.dennisguse.opentracks.content.provider.CustomSQLiteOpenHelper;
|
import de.dennisguse.opentracks.content.provider.CustomSQLiteOpenHelper;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
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}.
|
* Tests for {@link SearchEngine}.
|
||||||
* These are not meant to be quality tests, but instead feature-by-feature tests.
|
* These are not meant to be quality tests, but instead feature-by-feature tests.
|
||||||
@@ -74,7 +77,7 @@ public class SearchEngineTest {
|
|||||||
InstrumentationRegistry.getInstrumentation().getTargetContext().deleteDatabase(TAG + CustomSQLiteOpenHelper.DATABASE_NAME);
|
InstrumentationRegistry.getInstrumentation().getTargetContext().deleteDatabase(TAG + CustomSQLiteOpenHelper.DATABASE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertTrack(String title, String description, String category, long hoursAgo) {
|
private Track.Id insertTrack(String title, String description, String category, long hoursAgo) {
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
track.setName(title);
|
track.setName(title);
|
||||||
track.setDescription(description);
|
track.setDescription(description);
|
||||||
@@ -88,47 +91,47 @@ public class SearchEngineTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Uri uri = providerUtils.insertTrack(track);
|
Uri uri = providerUtils.insertTrack(track);
|
||||||
return ContentUris.parseId(uri);
|
return new Track.Id(ContentUris.parseId(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertTrack(String title, String description, String category) {
|
private Track.Id insertTrack(String title, String description, String category) {
|
||||||
return insertTrack(title, description, category, -1);
|
return insertTrack(title, description, category, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertTrack(String title, long hoursAgo) {
|
private Track.Id insertTrack(String title, long hoursAgo) {
|
||||||
return insertTrack(title, "", "", hoursAgo);
|
return insertTrack(title, "", "", hoursAgo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertWaypoint(String title, String description, String category, double distance, long hoursAgo, long trackId) {
|
private Marker.Id insertWaypoint(String title, String description, String category, double distance, long hoursAgo, Track.Id trackId) {
|
||||||
Location location = new Location(HERE);
|
Location location = new Location(HERE);
|
||||||
location.setLatitude(location.getLatitude() + distance);
|
location.setLatitude(location.getLatitude() + distance);
|
||||||
location.setLongitude(location.getLongitude() + distance);
|
location.setLongitude(location.getLongitude() + distance);
|
||||||
if (hoursAgo >= 0) {
|
if (hoursAgo >= 0) {
|
||||||
location.setTime(NOW - hoursAgo * 1000L * 60L * 60L);
|
location.setTime(NOW - hoursAgo * 1000L * 60L * 60L);
|
||||||
}
|
}
|
||||||
Waypoint waypoint = new Waypoint(location);
|
Marker waypoint = new Marker(location);
|
||||||
waypoint.setName(title);
|
waypoint.setName(title);
|
||||||
waypoint.setDescription(description);
|
waypoint.setDescription(description);
|
||||||
waypoint.setCategory(category);
|
waypoint.setCategory(category);
|
||||||
waypoint.setTrackId(trackId);
|
waypoint.setTrackId(trackId);
|
||||||
|
|
||||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
Uri uri = providerUtils.insertMarker(waypoint);
|
||||||
return ContentUris.parseId(uri);
|
return new Marker.Id(ContentUris.parseId(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
private long 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, -1);
|
return insertWaypoint(title, description, category, 0.0, -1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertWaypoint(String title, double distance) {
|
private Marker.Id insertWaypoint(String title, double distance) {
|
||||||
return insertWaypoint(title, "", "", distance, -1, -1);
|
return insertWaypoint(title, "", "", distance, -1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertWaypoint(String title, long hoursAgo) {
|
private Marker.Id insertWaypoint(String title, long hoursAgo) {
|
||||||
return insertWaypoint(title, "", "", 0.0, hoursAgo, -1);
|
return insertWaypoint(title, "", "", 0.0, hoursAgo, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertWaypoint(String title, long hoursAgo, long trackId) {
|
private Marker.Id insertWaypoint(String title, long hoursAgo, Track.Id trackId) {
|
||||||
return insertWaypoint(title, "", "", 0.0, hoursAgo, trackId);
|
return insertWaypoint(title, "", "", 0.0, hoursAgo, trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,14 +146,14 @@ public class SearchEngineTest {
|
|||||||
// - one which will match in title and description
|
// - one which will match in title and description
|
||||||
// - one which will match in all fields
|
// - one which will match in all fields
|
||||||
insertTrack("bb", "cc", "dd");
|
insertTrack("bb", "cc", "dd");
|
||||||
long descriptionMatchId = insertTrack("bb", "aa", "cc");
|
Track.Id descriptionMatchId = insertTrack("bb", "aa", "cc");
|
||||||
long categoryMatchId = insertTrack("bb", "cc", "aa");
|
Track.Id categoryMatchId = insertTrack("bb", "cc", "aa");
|
||||||
long titleMatchId = insertTrack("aa", "bb", "cc");
|
Track.Id titleMatchId = insertTrack("aa", "bb", "cc");
|
||||||
long titleCategoryMatchId = insertTrack("aa", "bb", "ca");
|
Track.Id titleCategoryMatchId = insertTrack("aa", "bb", "ca");
|
||||||
long titleDescriptionMatchId = insertTrack("aa", "ba", "cc");
|
Track.Id titleDescriptionMatchId = insertTrack("aa", "ba", "cc");
|
||||||
long allMatchId = insertTrack("aa", "ba", "ca");
|
Track.Id allMatchId = insertTrack("aa", "ba", "ca");
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Title > Description > Category.
|
// Title > Description > Category.
|
||||||
@@ -168,14 +171,14 @@ public class SearchEngineTest {
|
|||||||
// - one which will match in title and description
|
// - one which will match in title and description
|
||||||
// - one which will match in all fields
|
// - one which will match in all fields
|
||||||
insertWaypoint("bb", "cc", "dd");
|
insertWaypoint("bb", "cc", "dd");
|
||||||
long descriptionMatchId = insertWaypoint("bb", "aa", "cc");
|
Marker.Id descriptionMatchId = insertWaypoint("bb", "aa", "cc");
|
||||||
long categoryMatchId = insertWaypoint("bb", "cc", "aa");
|
Marker.Id categoryMatchId = insertWaypoint("bb", "cc", "aa");
|
||||||
long titleMatchId = insertWaypoint("aa", "bb", "cc");
|
Marker.Id titleMatchId = insertWaypoint("aa", "bb", "cc");
|
||||||
long titleCategoryMatchId = insertWaypoint("aa", "bb", "ca");
|
Marker.Id titleCategoryMatchId = insertWaypoint("aa", "bb", "ca");
|
||||||
long titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc");
|
Marker.Id titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc");
|
||||||
long allMatchId = insertWaypoint("aa", "ba", "ca");
|
Marker.Id allMatchId = insertWaypoint("aa", "ba", "ca");
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Title > Description > Category.
|
// Title > Description > Category.
|
||||||
@@ -190,17 +193,17 @@ public class SearchEngineTest {
|
|||||||
// - one waypoint which will match by title
|
// - one waypoint which will match by title
|
||||||
// - one track which won't match
|
// - one track which won't match
|
||||||
// - one track which will match by title
|
// - one track which will match by title
|
||||||
long descriptionWaypointId = insertWaypoint("bb", "aa", "cc");
|
Marker.Id descriptionWaypointId = insertWaypoint("bb", "aa", "cc");
|
||||||
insertWaypoint("bb", "cc", "dd");
|
insertWaypoint("bb", "cc", "dd");
|
||||||
long titleWaypointId = insertWaypoint("aa", "bb", "cc");
|
Marker.Id titleWaypointId = insertWaypoint("aa", "bb", "cc");
|
||||||
insertTrack("bb", "cc", "dd");
|
insertTrack("bb", "cc", "dd");
|
||||||
long trackId = insertTrack("aa", "bb", "cc");
|
Track.Id trackId = insertTrack("aa", "bb", "cc");
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Title > Description > Category.
|
// Title > Description > Category.
|
||||||
Assert.assertEquals(results.toString(), 3, results.size());
|
assertEquals(results.toString(), 3, results.size());
|
||||||
assertTrackResult(trackId, results.get(0));
|
assertTrackResult(trackId, results.get(0));
|
||||||
assertWaypointResult(titleWaypointId, results.get(1));
|
assertWaypointResult(titleWaypointId, results.get(1));
|
||||||
assertWaypointResult(descriptionWaypointId, results.get(2));
|
assertWaypointResult(descriptionWaypointId, results.get(2));
|
||||||
@@ -209,11 +212,11 @@ public class SearchEngineTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testSearchWaypointDistance() {
|
public void testSearchWaypointDistance() {
|
||||||
// All results match text, but they're at difference distances from the user.
|
// All results match text, but they're at difference distances from the user.
|
||||||
long farFarAwayId = insertWaypoint("aa", 0.3);
|
Marker.Id farFarAwayId = insertWaypoint("aa", 0.3);
|
||||||
long nearId = insertWaypoint("ab", 0.1);
|
Marker.Id nearId = insertWaypoint("ab", 0.1);
|
||||||
long farId = insertWaypoint("ac", 0.2);
|
Marker.Id farId = insertWaypoint("ac", 0.2);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", HERE, -1, NOW);
|
SearchQuery query = new SearchQuery("a", HERE, null, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Distance order.
|
// Distance order.
|
||||||
@@ -222,11 +225,11 @@ public class SearchEngineTest {
|
|||||||
|
|
||||||
public void testSearchTrackRecent() {
|
public void testSearchTrackRecent() {
|
||||||
// All results match text, but they're were recorded at different times.
|
// All results match text, but they're were recorded at different times.
|
||||||
long oldestId = insertTrack("aa", 3);
|
Track.Id oldestId = insertTrack("aa", 3);
|
||||||
long recentId = insertTrack("ab", 1);
|
Track.Id recentId = insertTrack("ab", 1);
|
||||||
long oldId = insertTrack("ac", 2);
|
Track.Id oldId = insertTrack("ac", 2);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Reverse time order.
|
// Reverse time order.
|
||||||
@@ -236,11 +239,11 @@ public class SearchEngineTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testSearchWaypointRecent() {
|
public void testSearchWaypointRecent() {
|
||||||
// All results match text, but they're were recorded at different times.
|
// All results match text, but they're were recorded at different times.
|
||||||
long oldestId = insertWaypoint("aa", 2);
|
Marker.Id oldestId = insertWaypoint("aa", 2);
|
||||||
long recentId = insertWaypoint("ab", 0);
|
Marker.Id recentId = insertWaypoint("ab", 0);
|
||||||
long oldId = insertWaypoint("ac", 1);
|
Marker.Id oldId = insertWaypoint("ac", 1);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Reverse time order.
|
// Reverse time order.
|
||||||
@@ -250,8 +253,8 @@ public class SearchEngineTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testSearchCurrentTrack() {
|
public void testSearchCurrentTrack() {
|
||||||
// All results match text, but one of them is the current track.
|
// All results match text, but one of them is the current track.
|
||||||
long currentId = insertTrack("ab", 1);
|
Track.Id currentId = insertTrack("ab", 1);
|
||||||
long otherId = insertTrack("aa", 1);
|
Track.Id otherId = insertTrack("aa", 1);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, currentId, NOW);
|
SearchQuery query = new SearchQuery("a", null, currentId, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
@@ -263,47 +266,57 @@ public class SearchEngineTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testSearchCurrentTrackWaypoint() {
|
public void testSearchCurrentTrackWaypoint() {
|
||||||
// All results match text, but one of them is in the current track.
|
// All results match text, but one of them is in the current track.
|
||||||
long otherId = insertWaypoint("aa", 1, 456);
|
Marker.Id otherId = insertWaypoint("aa", 1, new Track.Id(456));
|
||||||
long currentId = insertWaypoint("ab", 1, 123);
|
Marker.Id currentId = insertWaypoint("ab", 1, new Track.Id(123));
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, 123, NOW);
|
SearchQuery query = new SearchQuery("a", null, new Track.Id(123), NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Waypoint in current track should be promoted.
|
// Waypoint in current track should be promoted.
|
||||||
assertWaypointResults(results, currentId, otherId);
|
assertWaypointResults(results, currentId, otherId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTrackResult(long trackId, ScoredResult result) {
|
private void assertTrackResult(Track.Id trackId, ScoredResult result) {
|
||||||
Assert.assertNotNull("Not a track", result.track);
|
assertNotNull("Not a track", result.track);
|
||||||
Assert.assertNull("Ambiguous result", result.waypoint);
|
assertNull("Ambiguous result", result.marker);
|
||||||
Assert.assertEquals(trackId, result.track.getId());
|
assertEquals(trackId, result.track.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTrackResults(List<ScoredResult> results, long... trackIds) {
|
private void assertTrackResults(List<ScoredResult> results, Track.Id... trackIds) {
|
||||||
String errMsg = "Expected IDs=" + Arrays.toString(trackIds) + "; results=" + results;
|
long[] longTrackIds = new long[trackIds.length];
|
||||||
Assert.assertEquals(results.size(), trackIds.length);
|
for (int i = 0; i < trackIds.length; i++) {
|
||||||
|
longTrackIds[i] = trackIds[i].getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
String errMsg = "Expected IDs=" + Arrays.toString(longTrackIds) + "; results=" + results;
|
||||||
|
assertEquals(results.size(), trackIds.length);
|
||||||
for (int i = 0; i < results.size(); i++) {
|
for (int i = 0; i < results.size(); i++) {
|
||||||
ScoredResult result = results.get(i);
|
ScoredResult result = results.get(i);
|
||||||
Assert.assertNotNull(errMsg, result.track);
|
assertNotNull(errMsg, result.track);
|
||||||
Assert.assertNull(errMsg, result.waypoint);
|
assertNull(errMsg, result.marker);
|
||||||
Assert.assertEquals(errMsg, trackIds[i], result.track.getId());
|
assertEquals(errMsg, trackIds[i], result.track.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertWaypointResult(long waypointId, ScoredResult result) {
|
private void assertWaypointResult(Marker.Id waypointId, ScoredResult result) {
|
||||||
Assert.assertNotNull("Not a waypoint", result.waypoint);
|
assertNotNull("Not a waypoint", result.marker);
|
||||||
Assert.assertNull("Ambiguous result", result.track);
|
assertNull("Ambiguous result", result.track);
|
||||||
Assert.assertEquals(waypointId, result.waypoint.getId());
|
assertEquals(waypointId, result.marker.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertWaypointResults(List<ScoredResult> results, long... waypointIds) {
|
private void assertWaypointResults(List<ScoredResult> results, Marker.Id... waypointIds) {
|
||||||
String errMsg = "Expected IDs=" + Arrays.toString(waypointIds) + "; results=" + results;
|
long[] longWaypointIds = new long[waypointIds.length];
|
||||||
Assert.assertEquals(results.size(), waypointIds.length);
|
for (int i = 0; i < waypointIds.length; i++) {
|
||||||
|
longWaypointIds[i] = waypointIds[i].getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
String errMsg = "Expected IDs=" + Arrays.toString(longWaypointIds) + "; results=" + results;
|
||||||
|
assertEquals(results.size(), waypointIds.length);
|
||||||
for (int i = 0; i < results.size(); i++) {
|
for (int i = 0; i < results.size(); i++) {
|
||||||
ScoredResult result = results.get(i);
|
ScoredResult result = results.get(i);
|
||||||
Assert.assertNotNull(errMsg, result.waypoint);
|
assertNotNull(errMsg, result.marker);
|
||||||
Assert.assertNull(errMsg, result.track);
|
assertNull(errMsg, result.track);
|
||||||
Assert.assertEquals(errMsg, waypointIds[i], result.waypoint.getId());
|
assertEquals(errMsg, waypointIds[i], result.marker.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ public class TestDataUtil {
|
|||||||
/**
|
/**
|
||||||
* Create a track without any trackPoints.
|
* Create a track without any trackPoints.
|
||||||
*/
|
*/
|
||||||
public static Track createTrack(long trackId) {
|
public static Track createTrack(Track.Id trackId) {
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
track.setId(trackId);
|
track.setId(trackId);
|
||||||
track.setName("Test: " + trackId);
|
track.setName("Test: " + trackId.getId());
|
||||||
|
|
||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ public class TestDataUtil {
|
|||||||
* @param trackId the trackId of the track
|
* @param trackId the trackId of the track
|
||||||
* @param numPoints the trackPoints number in the track
|
* @param numPoints the trackPoints number in the track
|
||||||
*/
|
*/
|
||||||
public static Pair<Track, TrackPoint[]> createTrack(long trackId, int numPoints) {
|
public static Pair<Track, TrackPoint[]> createTrack(Track.Id trackId, int numPoints) {
|
||||||
Track track = createTrack(trackId);
|
Track track = createTrack(trackId);
|
||||||
|
|
||||||
TrackPoint[] trackPoints = new TrackPoint[numPoints];
|
TrackPoint[] trackPoints = new TrackPoint[numPoints];
|
||||||
@@ -45,7 +45,7 @@ public class TestDataUtil {
|
|||||||
return new Pair<>(track, trackPoints);
|
return new Pair<>(track, trackPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Track createTrackAndInsert(ContentProviderUtils contentProviderUtils, long trackId, int numPoints) {
|
public static Track createTrackAndInsert(ContentProviderUtils contentProviderUtils, Track.Id trackId, int numPoints) {
|
||||||
Pair<Track, TrackPoint[]> pair = createTrack(trackId, numPoints);
|
Pair<Track, TrackPoint[]> pair = createTrack(trackId, numPoints);
|
||||||
|
|
||||||
insertTrackWithLocations(contentProviderUtils, pair.first, pair.second);
|
insertTrackWithLocations(contentProviderUtils, pair.first, pair.second);
|
||||||
@@ -93,12 +93,12 @@ public class TestDataUtil {
|
|||||||
* @param location The location.
|
* @param location The location.
|
||||||
* @return the Waypoint created.
|
* @return the Waypoint created.
|
||||||
*/
|
*/
|
||||||
public static Waypoint createWaypointWithPhoto(Context context, long 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));
|
File dstFile = new File(FileUtils.getImageUrl(context, trackId));
|
||||||
dstFile.createNewFile();
|
dstFile.createNewFile();
|
||||||
Uri photoUri = FileUtils.getUriForFile(context, dstFile);
|
Uri photoUri = FileUtils.getUriForFile(context, dstFile);
|
||||||
String photoUrl = photoUri.toString();
|
String photoUrl = photoUri.toString();
|
||||||
|
|
||||||
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.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
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_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(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(MarkerColumns.CONTENT_TYPE, customContentProvider.getType(MarkerColumns.CONTENT_URI));
|
||||||
assertEquals(WaypointsColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(WaypointsColumns.CONTENT_URI.buildUpon(), 1).build()));
|
assertEquals(MarkerColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(MarkerColumns.CONTENT_URI.buildUpon(), 1).build()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+291
-282
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -18,9 +18,9 @@ import org.junit.runner.RunWith;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -45,7 +45,7 @@ public class CustomSQLiteOpenHelperTest {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static Map<String, String> getTableSQL(SQLiteDatabase db) {
|
public static Map<String, String> getTableSQL(SQLiteDatabase db) {
|
||||||
HashMap<String, String> tableSQL = new HashMap<>();
|
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) {
|
if (cursor != null) {
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
tableSQL.put(cursor.getString(0), cursor.getString(1));
|
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));
|
||||||
assertTrue(hasSqlCreate(db, TrackPointsColumns.CREATE_TABLE_INDEX));
|
assertTrue(hasSqlCreate(db, TrackPointsColumns.CREATE_TABLE_INDEX));
|
||||||
|
|
||||||
assertTrue(hasSqlCreate(db, WaypointsColumns.CREATE_TABLE));
|
assertTrue(hasSqlCreate(db, MarkerColumns.CREATE_TABLE));
|
||||||
assertTrue(hasSqlCreate(db, WaypointsColumns.CREATE_TABLE_INDEX));
|
assertTrue(hasSqlCreate(db, MarkerColumns.CREATE_TABLE_INDEX));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
@@ -140,13 +140,13 @@ public class CustomSQLiteOpenHelperTest {
|
|||||||
|
|
||||||
assertEquals(tablesByCreate.get(TracksColumns.TABLE_NAME), tableByUpgrade.get(TracksColumns.TABLE_NAME));
|
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(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
|
// then - verify custom indices
|
||||||
assertEquals(3, indicesByCreate.size());
|
assertEquals(3, indicesByCreate.size());
|
||||||
assertEquals(indicesByUpgrade.get(TracksColumns.TABLE_NAME), indicesByCreate.get(TracksColumns.TABLE_NAME));
|
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(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
|
@Test
|
||||||
|
|||||||
+18
-8
@@ -3,33 +3,43 @@ package de.dennisguse.opentracks.content.provider;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
public class ShareContentProviderTest {
|
public class ShareContentProviderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateandParseURI_invalid() {
|
public void testCreateAndParseURI_invalid() {
|
||||||
Uri uri = Uri.parse("content://de.dennisguse.opentracks.debug.content/tracks/1");
|
Uri uri = Uri.parse("content://de.dennisguse.opentracks.debug.content/tracks/1");
|
||||||
|
|
||||||
Assert.assertArrayEquals(new long[]{}, ShareContentProvider.parseURI(uri));
|
assertEquals(0, ShareContentProvider.parseURI(uri).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateandParseURI_valid() {
|
public void testCreateAndParseURI_valid() {
|
||||||
long[] trackIds = {1, 3, 5};
|
Set<Track.Id> trackIds = new HashSet<>();
|
||||||
|
trackIds.add(new Track.Id(1));
|
||||||
|
trackIds.add(new Track.Id(3));
|
||||||
|
trackIds.add(new Track.Id(5));
|
||||||
|
|
||||||
Pair<Uri, String> shareURIandMIME = ShareContentProvider.createURI(trackIds, "TrackName", TrackFileFormat.KML_ONLY_TRACK);
|
Pair<Uri, String> shareURIandMIME = ShareContentProvider.createURI(trackIds, "TrackName", TrackFileFormat.KML_ONLY_TRACK);
|
||||||
|
|
||||||
Assert.assertArrayEquals(trackIds, ShareContentProvider.parseURI(shareURIandMIME.first));
|
assertEquals(trackIds, ShareContentProvider.parseURI(shareURIandMIME.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateURIescapeFilename() {
|
public void testCreateURIescapeFilename() {
|
||||||
long[] trackIds = {1};
|
Set<Track.Id> trackIds = new HashSet<>();
|
||||||
|
trackIds.add(new Track.Id(1));
|
||||||
Pair<Uri, String> shareURIandMIME = ShareContentProvider.createURI(trackIds, "../../&1=1", TrackFileFormat.KML_ONLY_TRACK);
|
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 androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.util.UintUtils;
|
import de.dennisguse.opentracks.util.UintUtils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class SensorDataCyclingTest {
|
public class SensorDataCyclingTest {
|
||||||
|
|
||||||
@@ -21,7 +23,7 @@ public class SensorDataCyclingTest {
|
|||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(60, current.getCadence_rpm(), 0.01);
|
assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -34,7 +36,7 @@ public class SensorDataCyclingTest {
|
|||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(33.53, current.getCadence_rpm(), 0.01);
|
assertEquals(33.53, current.getCadence_rpm(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -47,7 +49,7 @@ public class SensorDataCyclingTest {
|
|||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// 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);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(current.hasCadence_rpm());
|
assertFalse(current.hasCadence_rpm());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -74,7 +76,7 @@ public class SensorDataCyclingTest {
|
|||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(60, current.getCadence_rpm(), 0.01);
|
assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,7 +89,7 @@ public class SensorDataCyclingTest {
|
|||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(60, current.getCadence_rpm(), 0.01);
|
assertEquals(60, current.getCadence_rpm(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -100,7 +102,7 @@ public class SensorDataCyclingTest {
|
|||||||
current.compute(previous, 2150);
|
current.compute(previous, 2150);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(1.20, current.getSpeed_mps(), 0.01);
|
assertEquals(1.20, current.getSpeed_mps(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -113,6 +115,6 @@ public class SensorDataCyclingTest {
|
|||||||
current.compute(previous, 2000);
|
current.compute(previous, 2000);
|
||||||
|
|
||||||
// then
|
// 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 androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
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.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.util.UnitConversions;
|
import de.dennisguse.opentracks.util.UnitConversions;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link ChartFragment}.
|
* Tests {@link ChartFragment}.
|
||||||
*
|
*
|
||||||
@@ -78,9 +79,9 @@ public class ChartFragmentTest {
|
|||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(Float.NaN, point.getHeartRate(), 0.01);
|
assertEquals(Float.NaN, point.getHeartRate(), 0.01);
|
||||||
Assert.assertEquals(Float.NaN, point.getCadence(), 0.01);
|
assertEquals(Float.NaN, point.getCadence(), 0.01);
|
||||||
Assert.assertEquals(Float.NaN, point.getPower(), 0.01);
|
assertEquals(Float.NaN, point.getPower(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,9 +99,9 @@ public class ChartFragmentTest {
|
|||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(100.0, point.getHeartRate(), 0.01);
|
assertEquals(100.0, point.getHeartRate(), 0.01);
|
||||||
Assert.assertEquals(101.0, point.getCadence(), 0.01);
|
assertEquals(101.0, point.getCadence(), 0.01);
|
||||||
Assert.assertEquals(102.0, point.getPower(), 0.01);
|
assertEquals(102.0, point.getPower(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,12 +113,12 @@ public class ChartFragmentTest {
|
|||||||
// Resets last location and writes first location.
|
// Resets last location and writes first location.
|
||||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
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.
|
// The second is a same location, just different time.
|
||||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
point = chartFragment.createPendingPoint(trackPoint2);
|
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.
|
// The third location is a new location, and use metric.
|
||||||
TrackPoint trackPoint3 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint3 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
@@ -129,7 +130,7 @@ public class ChartFragmentTest {
|
|||||||
Location.distanceBetween(trackPoint2.getLatitude(), trackPoint2.getLongitude(),
|
Location.distanceBetween(trackPoint2.getLatitude(), trackPoint2.getLongitude(),
|
||||||
trackPoint3.getLatitude(), trackPoint3.getLongitude(), results);
|
trackPoint3.getLatitude(), trackPoint3.getLongitude(), results);
|
||||||
double distance1 = results[0] * UnitConversions.M_TO_KM;
|
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.
|
// The fourth location is a new location, and use metric.
|
||||||
TrackPoint trackPoint4 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint4 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
@@ -140,7 +141,7 @@ public class ChartFragmentTest {
|
|||||||
Location.distanceBetween(trackPoint3.getLatitude(), trackPoint3.getLongitude(),
|
Location.distanceBetween(trackPoint3.getLatitude(), trackPoint3.getLongitude(),
|
||||||
trackPoint4.getLatitude(), trackPoint4.getLongitude(), results);
|
trackPoint4.getLatitude(), trackPoint4.getLongitude(), results);
|
||||||
double distance2 = results[0] * UnitConversions.M_TO_KM;
|
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.
|
// The first is a same location, just different time.
|
||||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
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.
|
// The second location is a new location, and use imperial.
|
||||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
@@ -170,7 +171,7 @@ public class ChartFragmentTest {
|
|||||||
float[] results = new float[4];
|
float[] results = new float[4];
|
||||||
Location.distanceBetween(trackPoint1.getLatitude(), trackPoint1.getLongitude(), trackPoint2.getLatitude(), trackPoint2.getLongitude(), results);
|
Location.distanceBetween(trackPoint1.getLatitude(), trackPoint1.getLongitude(), trackPoint2.getLatitude(), trackPoint2.getLongitude(), results);
|
||||||
double distance1 = results[0] * UnitConversions.M_TO_KM * UnitConversions.KM_TO_MI;
|
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.
|
// The third location is a new location, and use imperial.
|
||||||
TrackPoint trackPoint3 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint3 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
@@ -183,7 +184,7 @@ public class ChartFragmentTest {
|
|||||||
*/
|
*/
|
||||||
Location.distanceBetween(trackPoint2.getLatitude(), trackPoint2.getLongitude(), trackPoint3.getLatitude(), trackPoint3.getLongitude(), results);
|
Location.distanceBetween(trackPoint2.getLatitude(), trackPoint2.getLongitude(), trackPoint3.getLatitude(), trackPoint3.getLongitude(), results);
|
||||||
double distance2 = results[0] * UnitConversions.M_TO_KM * UnitConversions.KM_TO_MI;
|
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);
|
chartFragment.setChartByDistance(false);
|
||||||
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||||
Assert.assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
assertEquals(0.0, point.getTimeOrDistance(), 0.01);
|
||||||
long timeSpan = 222;
|
long timeSpan = 222;
|
||||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
trackPoint2.setTime(trackPoint1.getTime() + timeSpan);
|
trackPoint2.setTime(trackPoint1.getTime() + timeSpan);
|
||||||
point = chartFragment.createPendingPoint(trackPoint2);
|
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.
|
* Then only one value INITIAL_ALTITUDE in buffer.
|
||||||
*/
|
*/
|
||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
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.
|
* 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();
|
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
trackPoint2.setAltitude(TrackStubUtils.INITIAL_ALTITUDE * 2);
|
trackPoint2.setAltitude(TrackStubUtils.INITIAL_ALTITUDE * 2);
|
||||||
point = chartFragment.createPendingPoint(trackPoint2);
|
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();
|
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
trackPoint1.setSpeed(128.5f);
|
trackPoint1.setSpeed(128.5f);
|
||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
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.
|
* Tests the logic when both metricUnits and reportSpeed are true.
|
||||||
@@ -253,7 +254,7 @@ public class ChartFragmentTest {
|
|||||||
trackPoint2.setTime(trackPoint1.getTime() + 222);
|
trackPoint2.setTime(trackPoint1.getTime() + 222);
|
||||||
trackPoint2.setSpeed(130);
|
trackPoint2.setSpeed(130);
|
||||||
point = chartFragment.createPendingPoint(trackPoint2);
|
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();
|
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
trackPoint1.setSpeed(100.0f);
|
trackPoint1.setSpeed(100.0f);
|
||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||||
Assert.assertEquals(0.0, point.getSpeed(), 0.01);
|
assertEquals(0.0, point.getSpeed(), 0.01);
|
||||||
|
|
||||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
|
|
||||||
@@ -278,7 +279,7 @@ public class ChartFragmentTest {
|
|||||||
trackPoint2.setTime(trackPoint2.getTime() + 222);
|
trackPoint2.setTime(trackPoint2.getTime() + 222);
|
||||||
trackPoint2.setSpeed(102);
|
trackPoint2.setSpeed(102);
|
||||||
point = chartFragment.createPendingPoint(trackPoint2);
|
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();
|
TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
trackPoint1.setSpeed(100.0f);
|
trackPoint1.setSpeed(100.0f);
|
||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
ChartPoint point = chartFragment.createPendingPoint(trackPoint1);
|
||||||
Assert.assertEquals(0.0, point.getSpeed(), 0.01);
|
assertEquals(0.0, point.getSpeed(), 0.01);
|
||||||
|
|
||||||
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint();
|
||||||
|
|
||||||
@@ -303,7 +304,7 @@ public class ChartFragmentTest {
|
|||||||
trackPoint2.setTime(trackPoint2.getTime() + 222);
|
trackPoint2.setTime(trackPoint2.getTime() + 222);
|
||||||
trackPoint2.setSpeed(102);
|
trackPoint2.setSpeed(102);
|
||||||
point = chartFragment.createPendingPoint(trackPoint2);
|
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 trackPoint = TrackStubUtils.createDefaultTrackPoint();
|
||||||
trackPoint.setSpeed(0);
|
trackPoint.setSpeed(0);
|
||||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
||||||
Assert.assertEquals(0.0, point.getPace(), 0.01);
|
assertEquals(0.0, point.getPace(), 0.01);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -24,7 +24,6 @@ import android.net.Uri;
|
|||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
|
||||||
@@ -34,11 +33,12 @@ import java.util.Locale;
|
|||||||
import java.util.SimpleTimeZone;
|
import java.util.SimpleTimeZone;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.eq;
|
import static org.mockito.Mockito.eq;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -70,7 +70,7 @@ public abstract class AbstractTestFileTrackImporter {
|
|||||||
static final long TRACK_POINT_ID_3 = 4;
|
static final long TRACK_POINT_ID_3 = 4;
|
||||||
|
|
||||||
private static final long WAYPOINT_ID_0 = 1;
|
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();
|
protected final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
@@ -96,11 +96,11 @@ public abstract class AbstractTestFileTrackImporter {
|
|||||||
/**
|
/**
|
||||||
* Expects the first track point to be added.
|
* Expects the first track point to be added.
|
||||||
*
|
*
|
||||||
* @param trackPoint the trackPoint
|
* @param trackPoint the trackPoint
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
* @param trackPointId the track point id
|
* @param trackPointId the track point id
|
||||||
*/
|
*/
|
||||||
protected void expectFirstTrackPoint(TrackPoint trackPoint, long trackId, long trackPointId) {
|
protected void expectFirstTrackPoint(TrackPoint trackPoint, Track.Id trackId, long trackPointId) {
|
||||||
when(contentProviderUtils.bulkInsertTrackPoint(trackPoint != null ? (TrackPoint[]) any() : (TrackPoint[]) any(), eq(trackId))).thenReturn(1);
|
when(contentProviderUtils.bulkInsertTrackPoint(trackPoint != null ? (TrackPoint[]) any() : (TrackPoint[]) any(), eq(trackId))).thenReturn(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,10 +111,10 @@ public abstract class AbstractTestFileTrackImporter {
|
|||||||
* @param lastTrack true if it is the last track in the gpx
|
* @param lastTrack true if it is the last track in the gpx
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
protected void expectTrackUpdate(ArgumentCaptor<Track> trackCaptor, boolean lastTrack, long trackId) {
|
protected void expectTrackUpdate(ArgumentCaptor<Track> trackCaptor, boolean lastTrack, Track.Id trackId) {
|
||||||
contentProviderUtils.updateTrack(trackCaptor.capture());
|
contentProviderUtils.updateTrack(trackCaptor.capture());
|
||||||
|
|
||||||
when(contentProviderUtils.insertWaypoint(any())).thenReturn(WAYPOINT_ID_O_URI);
|
when(contentProviderUtils.insertMarker(any())).thenReturn(WAYPOINT_ID_O_URI);
|
||||||
if (lastTrack) {
|
if (lastTrack) {
|
||||||
// Return null to not add waypoints
|
// Return null to not add waypoints
|
||||||
when(contentProviderUtils.getTrack(trackId)).thenReturn(null);
|
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) {
|
protected void verifyTrack(Track track, String name, String description, long time) {
|
||||||
Assert.assertEquals(name, track.getName());
|
assertEquals(name, track.getName());
|
||||||
Assert.assertEquals(description, track.getDescription());
|
assertEquals(description, track.getDescription());
|
||||||
if (time != -1L) {
|
if (time != -1L) {
|
||||||
Assert.assertEquals(time, track.getTrackStatistics().getStartTime_ms());
|
assertEquals(time, track.getTrackStatistics().getStartTime_ms());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-44
@@ -21,10 +21,10 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
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.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||||
@@ -53,11 +53,11 @@ public class ExportImportTest {
|
|||||||
private static final String TRACK_CATEGORY = "the category";
|
private static final String TRACK_CATEGORY = "the category";
|
||||||
private static final String TRACK_DESCRIPTION = "the description";
|
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 final List<TrackPoint> trackPoints = new ArrayList<>();
|
||||||
|
|
||||||
private long importTrackId;
|
private Track.Id importTrackId;
|
||||||
private final long trackId = System.currentTimeMillis();
|
private final Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -72,19 +72,19 @@ public class ExportImportTest {
|
|||||||
trackPoints.addAll(Arrays.asList(track.second));
|
trackPoints.addAll(Arrays.asList(track.second));
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
Waypoint waypoint = new Waypoint(track.second[i].getLocation());
|
Marker marker = new Marker(track.second[i].getLocation());
|
||||||
waypoint.setName("the waypoint " + i);
|
marker.setName("the marker " + i);
|
||||||
waypoint.setDescription("the waypoint description " + i);
|
marker.setDescription("the marker description " + i);
|
||||||
waypoint.setCategory("the waypoint category" + i);
|
marker.setCategory("the marker category" + i);
|
||||||
waypoint.setIcon("the waypoing icon" + i);
|
marker.setIcon("the waypoing icon" + i);
|
||||||
waypoint.setPhotoUrl("the photo url" + i);
|
marker.setPhotoUrl("the photo url" + i);
|
||||||
waypoint.setTrackId(trackId);
|
marker.setTrackId(trackId);
|
||||||
contentProviderUtils.insertWaypoint(waypoint);
|
contentProviderUtils.insertMarker(marker);
|
||||||
|
|
||||||
waypoints.add(waypoint);
|
markers.add(marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(waypoints.size(), contentProviderUtils.getWaypointCount(trackId));
|
assertEquals(markers.size(), contentProviderUtils.getMarkerCount(trackId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -106,12 +106,12 @@ public class ExportImportTest {
|
|||||||
// given
|
// given
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL.newTrackExporter(context, new Track[]{track});
|
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL.newTrackExporter(context);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
trackExporter.writeTrack(context, outputStream);
|
trackExporter.writeTrack(track, outputStream);
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
@@ -129,8 +129,8 @@ public class ExportImportTest {
|
|||||||
assertEquals(track.getIcon(), importedTrack.getIcon());
|
assertEquals(track.getIcon(), importedTrack.getIcon());
|
||||||
assertEquals(track.getUuid(), importedTrack.getUuid());
|
assertEquals(track.getUuid(), importedTrack.getUuid());
|
||||||
|
|
||||||
// 2. waypoints
|
// 2. markers
|
||||||
assertWaypoints();
|
assertMarkers();
|
||||||
|
|
||||||
// 3. trackpoints
|
// 3. trackpoints
|
||||||
assertTrackpoints(false, false, false);
|
assertTrackpoints(false, false, false);
|
||||||
@@ -142,12 +142,12 @@ public class ExportImportTest {
|
|||||||
// given
|
// given
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.newTrackExporter(context, new Track[]{track});
|
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.newTrackExporter(context);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
trackExporter.writeTrack(context, outputStream);
|
trackExporter.writeTrack(track, outputStream);
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
@@ -164,8 +164,8 @@ public class ExportImportTest {
|
|||||||
assertEquals(track.getName(), importedTrack.getName());
|
assertEquals(track.getName(), importedTrack.getName());
|
||||||
assertEquals(track.getIcon(), importedTrack.getIcon());
|
assertEquals(track.getIcon(), importedTrack.getIcon());
|
||||||
|
|
||||||
// 2. waypoints
|
// 2. markers
|
||||||
assertWaypoints();
|
assertMarkers();
|
||||||
|
|
||||||
// 3. trackpoints
|
// 3. trackpoints
|
||||||
assertTrackpoints(true, true, true);
|
assertTrackpoints(true, true, true);
|
||||||
@@ -178,12 +178,12 @@ public class ExportImportTest {
|
|||||||
PreferencesUtils.setBoolean(context, R.string.import_prevent_reimport_key, true);
|
PreferencesUtils.setBoolean(context, R.string.import_prevent_reimport_key, true);
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.newTrackExporter(context, new Track[]{track});
|
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.newTrackExporter(context);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
trackExporter.writeTrack(context, outputStream);
|
trackExporter.writeTrack(track, outputStream);
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||||
@@ -229,12 +229,12 @@ public class ExportImportTest {
|
|||||||
// given
|
// given
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
TrackExporter trackExporter = TrackFileFormat.GPX.newTrackExporter(context, new Track[]{track});
|
TrackExporter trackExporter = TrackFileFormat.GPX.newTrackExporter(context);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
trackExporter.writeTrack(context, outputStream);
|
trackExporter.writeTrack(track, outputStream);
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
@@ -253,8 +253,8 @@ public class ExportImportTest {
|
|||||||
//TODO exporting and importing a track icon is not yet supported by GpxTrackWriter.
|
//TODO exporting and importing a track icon is not yet supported by GpxTrackWriter.
|
||||||
//assertEquals(track.getIcon(), trackImported.getIcon());
|
//assertEquals(track.getIcon(), trackImported.getIcon());
|
||||||
|
|
||||||
// 2. waypoints
|
// 2. markers
|
||||||
assertWaypoints();
|
assertMarkers();
|
||||||
|
|
||||||
// 3. trackpoints
|
// 3. trackpoints
|
||||||
assertTrackpoints(false, true, true);
|
assertTrackpoints(false, true, true);
|
||||||
@@ -267,12 +267,12 @@ public class ExportImportTest {
|
|||||||
PreferencesUtils.setBoolean(context, R.string.import_prevent_reimport_key, true);
|
PreferencesUtils.setBoolean(context, R.string.import_prevent_reimport_key, true);
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
TrackExporter trackExporter = TrackFileFormat.GPX.newTrackExporter(context, new Track[]{track});
|
TrackExporter trackExporter = TrackFileFormat.GPX.newTrackExporter(context);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
trackExporter.writeTrack(context, outputStream);
|
trackExporter.writeTrack(track, outputStream);
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||||
@@ -285,22 +285,22 @@ public class ExportImportTest {
|
|||||||
assertNull(trackImported);
|
assertNull(trackImported);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertWaypoints() {
|
private void assertMarkers() {
|
||||||
assertEquals(waypoints.size(), contentProviderUtils.getWaypointCount(importTrackId));
|
assertEquals(markers.size(), contentProviderUtils.getMarkerCount(importTrackId));
|
||||||
|
|
||||||
List<Waypoint> importedWaypoints = contentProviderUtils.getWaypoints(importTrackId);
|
List<Marker> importedMarkers = contentProviderUtils.getMarkers(importTrackId);
|
||||||
for (int i = 0; i < waypoints.size(); i++) {
|
for (int i = 0; i < markers.size(); i++) {
|
||||||
Waypoint waypoint = waypoints.get(i);
|
Marker marker = markers.get(i);
|
||||||
Waypoint importedWaypoint = importedWaypoints.get(i);
|
Marker importMarker = importedMarkers.get(i);
|
||||||
assertEquals(waypoint.getCategory(), importedWaypoint.getCategory());
|
assertEquals(marker.getCategory(), importMarker.getCategory());
|
||||||
assertEquals(waypoint.getDescription(), importedWaypoint.getDescription());
|
assertEquals(marker.getDescription(), importMarker.getDescription());
|
||||||
// assertEquals(waypoint.getIcon(), importedWaypoint.getIcon()); // TODO for KML
|
// assertEquals(marker.getIcon(), importMarker.getIcon()); // TODO for KML
|
||||||
assertEquals(waypoint.getName(), importedWaypoint.getName());
|
assertEquals(marker.getName(), importMarker.getName());
|
||||||
assertEquals("", importedWaypoint.getPhotoUrl());
|
assertEquals("", importMarker.getPhotoUrl());
|
||||||
|
|
||||||
assertEquals(waypoint.getLocation().getLatitude(), importedWaypoint.getLocation().getLatitude(), 0.001);
|
assertEquals(marker.getLocation().getLatitude(), importMarker.getLocation().getLatitude(), 0.001);
|
||||||
assertEquals(waypoint.getLocation().getLongitude(), importedWaypoint.getLocation().getLongitude(), 0.001);
|
assertEquals(marker.getLocation().getLongitude(), importMarker.getLocation().getLongitude(), 0.001);
|
||||||
assertEquals(waypoint.getLocation().getAltitude(), importedWaypoint.getLocation().getAltitude(), 0.001);
|
assertEquals(marker.getLocation().getAltitude(), importMarker.getLocation().getAltitude(), 0.001);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.services;
|
package de.dennisguse.opentracks.services;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -23,6 +22,8 @@ import org.junit.runners.JUnit4;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.services.handlers.AdaptiveLocationListenerPolicy;
|
import de.dennisguse.opentracks.services.handlers.AdaptiveLocationListenerPolicy;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the {@link AdaptiveLocationListenerPolicy}.
|
* Tests the {@link AdaptiveLocationListenerPolicy}.
|
||||||
*
|
*
|
||||||
@@ -57,17 +58,17 @@ public class AdaptiveLocationListenerPolicyTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testGetDesiredPollingInterval() {
|
public void testGetDesiredPollingInterval() {
|
||||||
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_BIG);
|
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_BIG);
|
||||||
Assert.assertEquals(MAX, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
assertEquals(MAX, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||||
|
|
||||||
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_NORMAL);
|
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_NORMAL);
|
||||||
// First get the half of NEW_IDLE_TIME_NORMAL, and then round it to the nearest second.
|
// 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);
|
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_SMALL);
|
||||||
Assert.assertEquals(MIN, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
assertEquals(MIN, adaptiveLocationListenerPolicy.getDesiredPollingInterval());
|
||||||
|
|
||||||
adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_LESS_THAN_MIN);
|
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
|
@Test
|
||||||
public void testGetMinDistance() {
|
public void testGetMinDistance() {
|
||||||
Assert.assertEquals(MIN_DISTANCE, adaptiveLocationListenerPolicy.getMinDistance_m());
|
assertEquals(MIN_DISTANCE, adaptiveLocationListenerPolicy.getMinDistance_m());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+68
-53
@@ -21,6 +21,7 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
@@ -31,8 +32,8 @@ import androidx.test.rule.GrantPermissionRule;
|
|||||||
import androidx.test.rule.ServiceTestRule;
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -43,15 +44,22 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
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.
|
* Tests for the track recording service.
|
||||||
*
|
*
|
||||||
@@ -69,10 +77,17 @@ public class TrackRecordingServiceTest {
|
|||||||
@Rule
|
@Rule
|
||||||
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void preSetUp() {
|
||||||
|
// Prepare looper for Android's message queue
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
private final long trackId = Math.abs(new Random().nextLong());
|
private final Track.Id trackId = new Track.Id(Math.abs(new Random().nextLong()));
|
||||||
|
|
||||||
static Intent createStartIntent(Context context) {
|
static Intent createStartIntent(Context context) {
|
||||||
return new Intent(context, TrackRecordingService.class);
|
return new Intent(context, TrackRecordingService.class);
|
||||||
@@ -111,22 +126,22 @@ public class TrackRecordingServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testStartable() throws TimeoutException {
|
public void testStartable() throws TimeoutException {
|
||||||
mServiceRule.startService(createStartIntent(context));
|
mServiceRule.startService(createStartIntent(context));
|
||||||
Assert.assertNotNull(mServiceRule.bindService(createStartIntent(context)));
|
assertNotNull(mServiceRule.bindService(createStartIntent(context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testBindable() throws TimeoutException {
|
public void testBindable() throws TimeoutException {
|
||||||
IBinder service = mServiceRule.bindService(createStartIntent(context));
|
IBinder service = mServiceRule.bindService(createStartIntent(context));
|
||||||
Assert.assertNotNull(service);
|
assertNotNull(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testRecording_noTracks() throws Exception {
|
public void testRecording_noTracks() throws Exception {
|
||||||
// given
|
// given
|
||||||
List<Track> tracks = contentProviderUtils.getAllTracks();
|
List<Track> tracks = contentProviderUtils.getTracks();
|
||||||
Assert.assertTrue(tracks.isEmpty());
|
assertTrue(tracks.isEmpty());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Intent startIntent = createStartIntent(context);
|
Intent startIntent = createStartIntent(context);
|
||||||
@@ -135,8 +150,8 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
// Test if we start in no-recording mode by default.
|
// Test if we start in no-recording mode by default.
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
Assert.assertEquals(-1L, service.getRecordingTrackId());
|
assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -149,8 +164,8 @@ public class TrackRecordingServiceTest {
|
|||||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
Assert.assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, service.getRecordingTrackId());
|
assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -163,7 +178,7 @@ public class TrackRecordingServiceTest {
|
|||||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -178,21 +193,21 @@ public class TrackRecordingServiceTest {
|
|||||||
service.pauseCurrentTrack();
|
service.pauseCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
|
assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
|
||||||
|
|
||||||
//when
|
//when
|
||||||
service.resumeTrack(trackId);
|
service.resumeTrack(trackId);
|
||||||
newTrackPoint(service);
|
newTrackPoint(service);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
assertEquals(trackId, service.getRecordingTrackId());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||||
Assert.assertEquals(5, trackPoints.size());
|
assertEquals(5, trackPoints.size());
|
||||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
||||||
Assert.assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(3).getLatitude(), 0.01);
|
assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(3).getLatitude(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -204,20 +219,20 @@ public class TrackRecordingServiceTest {
|
|||||||
newTrackPoint(service);
|
newTrackPoint(service);
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
Assert.assertEquals(1, contentProviderUtils.getTrackPoints(trackId).size());
|
assertEquals(1, contentProviderUtils.getTrackPoints(trackId).size());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
service.resumeTrack(trackId);
|
service.resumeTrack(trackId);
|
||||||
newTrackPoint(service);
|
newTrackPoint(service);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
assertEquals(trackId, service.getRecordingTrackId());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||||
Assert.assertEquals(4, trackPoints.size());
|
assertEquals(4, trackPoints.size());
|
||||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||||
Assert.assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FlakyTest(detail = "Sometimes fails on CI.")
|
@FlakyTest(detail = "Sometimes fails on CI.")
|
||||||
@@ -233,8 +248,8 @@ public class TrackRecordingServiceTest {
|
|||||||
PreferencesUtils.setLong(context, R.string.recording_track_id_key, 123L);
|
PreferencesUtils.setLong(context, R.string.recording_track_id_key, 123L);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
Assert.assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, service.getRecordingTrackId());
|
assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -243,18 +258,18 @@ public class TrackRecordingServiceTest {
|
|||||||
// given
|
// given
|
||||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||||
service.startNewTrack();
|
service.startNewTrack();
|
||||||
Assert.assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
|
|
||||||
long trackId = service.getRecordingTrackId();
|
Track.Id trackId = service.getRecordingTrackId();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
long newTrackId = service.startNewTrack();
|
Track.Id newTrackId = service.startNewTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, newTrackId);
|
assertNull(newTrackId);
|
||||||
|
|
||||||
Assert.assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
||||||
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
assertEquals(trackId, service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -262,15 +277,15 @@ public class TrackRecordingServiceTest {
|
|||||||
public void testEndCurrentTrack_noRecording() throws Exception {
|
public void testEndCurrentTrack_noRecording() throws Exception {
|
||||||
// given
|
// given
|
||||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
// Ending the current track when there is no recording should not result in any error.
|
// Ending the current track when there is no recording should not result in any error.
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(PreferencesUtils.isRecording(context));
|
assertFalse(PreferencesUtils.isRecording(context));
|
||||||
Assert.assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, service.getRecordingTrackId());
|
assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -278,13 +293,13 @@ public class TrackRecordingServiceTest {
|
|||||||
public void testInsertWaypointMarker_noRecordingTrack() throws Exception {
|
public void testInsertWaypointMarker_noRecordingTrack() throws Exception {
|
||||||
// given
|
// given
|
||||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
long waypointId = service.insertWaypoint(null, null, null, null);
|
Marker.Id waypointId = service.insertMarker(null, null, null, null);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(-1L, waypointId);
|
assertNull(waypointId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -293,35 +308,35 @@ public class TrackRecordingServiceTest {
|
|||||||
// given
|
// given
|
||||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||||
service.startNewTrack();
|
service.startNewTrack();
|
||||||
Assert.assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
newTrackPoint(service);
|
newTrackPoint(service);
|
||||||
long trackId = service.getRecordingTrackId();
|
Track.Id trackId = service.getRecordingTrackId();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
long waypointId = service.insertWaypoint(null, null, null, null);
|
Marker.Id waypointId = service.insertMarker(null, null, null, null);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertNotEquals(-1L, waypointId);
|
assertNotEquals(-1L, waypointId);
|
||||||
Waypoint wpt = contentProviderUtils.getWaypoint(waypointId);
|
Marker wpt = contentProviderUtils.getMarker(waypointId);
|
||||||
Assert.assertEquals(context.getString(R.string.marker_waypoint_icon_url), wpt.getIcon());
|
assertEquals(context.getString(R.string.marker_waypoint_icon_url), wpt.getIcon());
|
||||||
Assert.assertEquals(context.getString(R.string.marker_name_format, 1), wpt.getName());
|
assertEquals(context.getString(R.string.marker_name_format, 1), wpt.getName());
|
||||||
Assert.assertEquals(trackId, wpt.getTrackId());
|
assertEquals(trackId, wpt.getTrackId());
|
||||||
Assert.assertEquals(0.0, wpt.getLength(), 0.01);
|
assertEquals(0.0, wpt.getLength(), 0.01);
|
||||||
Assert.assertNotNull(wpt.getLocation());
|
assertNotNull(wpt.getLocation());
|
||||||
|
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addTrack(Track track, boolean isRecording) {
|
private void addTrack(Track track, boolean isRecording) {
|
||||||
Assert.assertTrue(track.getId() >= 0);
|
assertTrue(track.getId().isValid());
|
||||||
contentProviderUtils.insertTrack(track);
|
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() : PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
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);
|
PreferencesUtils.setBoolean(context, R.string.recording_track_paused_key, !isRecording);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Do not use to create a track that is currently recording.
|
// NOTE: Do not use to create a track that is currently recording.
|
||||||
private void createDummyTrack(long id, long stopTime, boolean isRecording) {
|
private void createDummyTrack(Track.Id id, long stopTime, boolean isRecording) {
|
||||||
Track dummyTrack = new Track();
|
Track dummyTrack = new Track();
|
||||||
dummyTrack.setId(id);
|
dummyTrack.setId(id);
|
||||||
dummyTrack.setName("Dummy Track");
|
dummyTrack.setName("Dummy Track");
|
||||||
|
|||||||
+44
-41
@@ -12,7 +12,6 @@ import androidx.test.rule.GrantPermissionRule;
|
|||||||
import androidx.test.rule.ServiceTestRule;
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@@ -23,6 +22,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
@@ -32,6 +32,9 @@ import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
|||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests insert location.
|
* Tests insert location.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -89,7 +92,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
@Test
|
@Test
|
||||||
public void testOnLocationChangedAsync_movingAccurate() throws Exception {
|
public void testOnLocationChangedAsync_movingAccurate() throws Exception {
|
||||||
// given
|
// given
|
||||||
long trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 15);
|
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 15);
|
||||||
@@ -102,18 +105,18 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||||
Assert.assertEquals(6, trackPoints.size());
|
assertEquals(6, trackPoints.size());
|
||||||
Assert.assertEquals(45.0005, trackPoints.get(5).getLatitude(), 0.01);
|
assertEquals(45.0005, trackPoints.get(5).getLatitude(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testOnLocationChangedAsync_slowMovingAccurate() throws Exception {
|
public void testOnLocationChangedAsync_slowMovingAccurate() throws Exception {
|
||||||
// given
|
// given
|
||||||
long trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 15);
|
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 15);
|
||||||
@@ -126,11 +129,11 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||||
Assert.assertEquals(2, trackPoints.size());
|
assertEquals(2, trackPoints.size());
|
||||||
Assert.assertEquals(45.000005, trackPoints.get(1).getLatitude(), 0.01);
|
assertEquals(45.000005, trackPoints.get(1).getLatitude(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @MediumTest
|
// @MediumTest
|
||||||
@@ -155,7 +158,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
@Test
|
@Test
|
||||||
public void testOnLocationChangedAsync_idle() throws Exception {
|
public void testOnLocationChangedAsync_idle() throws Exception {
|
||||||
// given
|
// given
|
||||||
long trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 0);
|
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 0);
|
||||||
@@ -168,20 +171,20 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||||
Assert.assertEquals(3, trackPoints.size());
|
assertEquals(3, trackPoints.size());
|
||||||
Assert.assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(6, trackPoints.get(2).getAccuracy(), 0.01);
|
assertEquals(6, trackPoints.get(2).getAccuracy(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testOnLocationChangedAsync_idle_withMovement() throws Exception {
|
public void testOnLocationChangedAsync_idle_withMovement() throws Exception {
|
||||||
// given
|
// given
|
||||||
long trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 15);
|
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 15);
|
||||||
@@ -194,14 +197,14 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||||
Assert.assertEquals(4, trackPoints.size());
|
assertEquals(4, trackPoints.size());
|
||||||
Assert.assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(5, trackPoints.get(2).getAccuracy(), 0.01); //TODO Check why this trackPoint is inserted.
|
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(6, trackPoints.get(3).getAccuracy(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -209,7 +212,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
@Test
|
@Test
|
||||||
public void testOnLocationChangedAsync_idle_withSensorData() throws Exception {
|
public void testOnLocationChangedAsync_idle_withSensorData() throws Exception {
|
||||||
// given
|
// given
|
||||||
long trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
|
||||||
service.setRemoteSensorManager(new BluetoothRemoteSensorManager(context) {
|
service.setRemoteSensorManager(new BluetoothRemoteSensorManager(context) {
|
||||||
|
|
||||||
@@ -237,23 +240,23 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||||
Assert.assertEquals(6, trackPoints.size());
|
assertEquals(6, trackPoints.size());
|
||||||
Assert.assertEquals(0, trackPoints.get(0).getAccuracy(), 0.01);
|
assertEquals(0, trackPoints.get(0).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(1, trackPoints.get(1).getAccuracy(), 0.01);
|
assertEquals(1, trackPoints.get(1).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(4, trackPoints.get(4).getAccuracy(), 0.01);
|
assertEquals(4, trackPoints.get(4).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(5, trackPoints.get(5).getAccuracy(), 0.01);
|
assertEquals(5, trackPoints.get(5).getAccuracy(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testOnLocationChangedAsync_segment() throws Exception {
|
public void testOnLocationChangedAsync_segment() throws Exception {
|
||||||
// given
|
// given
|
||||||
long trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 0);
|
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 0);
|
||||||
@@ -265,16 +268,16 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||||
Assert.assertEquals(7, trackPoints.size());
|
assertEquals(7, trackPoints.size());
|
||||||
Assert.assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||||
Assert.assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(4).getLatitude(), 0.01);
|
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(4).getLatitude(), 0.01);
|
||||||
Assert.assertEquals(4, trackPoints.get(5).getAccuracy(), 0.01);
|
assertEquals(4, trackPoints.get(5).getAccuracy(), 0.01);
|
||||||
Assert.assertEquals(5, trackPoints.get(6).getAccuracy(), 0.01);
|
assertEquals(5, trackPoints.get(6).getAccuracy(), 0.01);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-21
@@ -13,7 +13,6 @@ import androidx.test.rule.ServiceTestRule;
|
|||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
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.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
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}.
|
* Tests for the track recording service, which require a {@link Looper}.
|
||||||
*
|
*
|
||||||
@@ -187,24 +192,24 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testIntegration_completeRecordingSession() throws TimeoutException {
|
public void testIntegration_completeRecordingSession() throws TimeoutException {
|
||||||
List<Track> tracks = contentProviderUtils.getAllTracks();
|
List<Track> tracks = contentProviderUtils.getTracks();
|
||||||
Assert.assertTrue(tracks.isEmpty());
|
assertTrue(tracks.isEmpty());
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fullRecordingSession() throws TimeoutException {
|
private void fullRecordingSession() throws TimeoutException {
|
||||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)));
|
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)));
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
// Start a track.
|
// Start a track.
|
||||||
long id = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
Assert.assertTrue(id >= 0);
|
assertTrue(trackId.isValid());
|
||||||
Assert.assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
Track track = contentProviderUtils.getTrack(id);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
Assert.assertNotNull(track);
|
assertNotNull(track);
|
||||||
Assert.assertEquals(id, track.getId());
|
assertEquals(trackId, track.getId());
|
||||||
Assert.assertEquals(id, PreferencesUtils.getRecordingTrackId(context));
|
assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
||||||
Assert.assertEquals(id, service.getRecordingTrackId());
|
assertEquals(trackId, service.getRecordingTrackId());
|
||||||
|
|
||||||
// Insert a few points, markers and statistics.
|
// Insert a few points, markers and statistics.
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
@@ -221,20 +226,20 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
service.newTrackPoint(trackPoint, prefAccuracy);
|
service.newTrackPoint(trackPoint, prefAccuracy);
|
||||||
|
|
||||||
if (i % 7 == 0) {
|
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.
|
// Stop the track. Validate if it has correct data.
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
Assert.assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
Assert.assertEquals(-1L, service.getRecordingTrackId());
|
assertNull(service.getRecordingTrackId());
|
||||||
track = contentProviderUtils.getTrack(id);
|
track = contentProviderUtils.getTrack(trackId);
|
||||||
Assert.assertNotNull(track);
|
assertNotNull(track);
|
||||||
Assert.assertEquals(id, track.getId());
|
assertEquals(trackId, track.getId());
|
||||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||||
Assert.assertNotNull(trackStatistics);
|
assertNotNull(trackStatistics);
|
||||||
Assert.assertTrue(trackStatistics.getStartTime_ms() > 0);
|
assertTrue(trackStatistics.getStartTime_ms() > 0);
|
||||||
Assert.assertTrue(trackStatistics.getStopTime_ms() >= trackStatistics.getStartTime_ms());
|
assertTrue(trackStatistics.getStopTime_ms() >= trackStatistics.getStartTime_ms());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -23,11 +23,12 @@ import androidx.test.core.app.ApplicationProvider;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link AnnouncementPeriodicTaskFactory}.
|
* Tests for {@link AnnouncementPeriodicTaskFactory}.
|
||||||
*
|
*
|
||||||
@@ -53,6 +54,6 @@ public class AnnouncementPeriodicTaskFactoryTest {
|
|||||||
public void testCreate() {
|
public void testCreate() {
|
||||||
PeriodicTaskFactory factory = new AnnouncementPeriodicTaskFactory();
|
PeriodicTaskFactory factory = new AnnouncementPeriodicTaskFactory();
|
||||||
PeriodicTask task = factory.create(context);
|
PeriodicTask task = factory.create(context);
|
||||||
Assert.assertTrue(task instanceof AnnouncementPeriodicTask);
|
assertTrue(task instanceof AnnouncementPeriodicTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.stats;
|
package de.dennisguse.opentracks.stats;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link TrackStatistics}.
|
* Tests for {@link TrackStatistics}.
|
||||||
* This only tests non-trivial pieces of that class.
|
* This only tests non-trivial pieces of that class.
|
||||||
@@ -61,28 +62,28 @@ public class TrackStatisticsTest {
|
|||||||
|
|
||||||
statistics.merge(statistics2);
|
statistics.merge(statistics2);
|
||||||
|
|
||||||
Assert.assertEquals(1000L, statistics.getStartTime_ms());
|
assertEquals(1000L, statistics.getStartTime_ms());
|
||||||
Assert.assertEquals(4000L, statistics.getStopTime_ms());
|
assertEquals(4000L, statistics.getStopTime_ms());
|
||||||
Assert.assertEquals(2500L, statistics.getTotalTime());
|
assertEquals(2500L, statistics.getTotalTime());
|
||||||
Assert.assertEquals(1300L, statistics.getMovingTime());
|
assertEquals(1300L, statistics.getMovingTime());
|
||||||
Assert.assertEquals(1100.0, statistics.getTotalDistance(), 0.001);
|
assertEquals(1100.0, statistics.getTotalDistance(), 0.001);
|
||||||
Assert.assertEquals(900.0, statistics.getTotalElevationGain(), 0.001);
|
assertEquals(900.0, statistics.getTotalElevationGain(), 0.001);
|
||||||
Assert.assertEquals(statistics.getTotalDistance() / (statistics.getMovingTime() / 1000.0), statistics.getMaxSpeed(), 0.001);
|
assertEquals(statistics.getTotalDistance() / (statistics.getMovingTime() / 1000.0), statistics.getMaxSpeed(), 0.001);
|
||||||
Assert.assertEquals(1200.0, statistics.getMinElevation(), 0.001);
|
assertEquals(1200.0, statistics.getMinElevation(), 0.001);
|
||||||
Assert.assertEquals(3575.0, statistics.getMaxElevation(), 0.001);
|
assertEquals(3575.0, statistics.getMaxElevation(), 0.001);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAverageSpeed() {
|
public void testGetAverageSpeed() {
|
||||||
statistics.setTotalDistance(1000.0);
|
statistics.setTotalDistance(1000.0);
|
||||||
statistics.setTotalTime(50000); // in milliseconds
|
statistics.setTotalTime(50000); // in milliseconds
|
||||||
Assert.assertEquals(20.0, statistics.getAverageSpeed(), 0.001);
|
assertEquals(20.0, statistics.getAverageSpeed(), 0.001);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAverageMovingSpeed() {
|
public void testGetAverageMovingSpeed() {
|
||||||
statistics.setTotalDistance(1000.0);
|
statistics.setTotalDistance(1000.0);
|
||||||
statistics.setMovingTime(20000); // in milliseconds
|
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.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
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.stats.TrackStatistics;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class AnnouncementUtilsTest {
|
public class AnnouncementUtilsTest {
|
||||||
@@ -26,9 +35,50 @@ public class AnnouncementUtilsTest {
|
|||||||
stats.setTotalElevationGain(6000);
|
stats.setTotalElevationGain(6000);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane");
|
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane", null);
|
||||||
|
|
||||||
// then
|
// 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 = " With a current kilometer 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 android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
|
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
public class BluetoothUtilsTest {
|
public class BluetoothUtilsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -19,7 +21,7 @@ public class BluetoothUtilsTest {
|
|||||||
int heartRate = BluetoothUtils.parseHeartRate(characteristic);
|
int heartRate = BluetoothUtils.parseHeartRate(characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(60, heartRate);
|
assertEquals(60, heartRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -32,7 +34,7 @@ public class BluetoothUtilsTest {
|
|||||||
int heartRate = BluetoothUtils.parseHeartRate(characteristic);
|
int heartRate = BluetoothUtils.parseHeartRate(characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(257, heartRate);
|
assertEquals(257, heartRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -44,8 +46,8 @@ public class BluetoothUtilsTest {
|
|||||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||||
Assert.assertNull(sensor.getSpeed());
|
assertNull(sensor.getSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -57,8 +59,8 @@ public class BluetoothUtilsTest {
|
|||||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertNull(sensor.getCadence());
|
assertNull(sensor.getCadence());
|
||||||
Assert.assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -70,7 +72,7 @@ public class BluetoothUtilsTest {
|
|||||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||||
Assert.assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
@@ -23,6 +22,8 @@ import org.junit.runners.JUnit4;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link FileUtils}.
|
* Tests for {@link FileUtils}.
|
||||||
*
|
*
|
||||||
@@ -37,7 +38,7 @@ public class FileUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testBuildUniqueFileName_new() {
|
public void testBuildUniqueFileName_new() {
|
||||||
String filename = FileUtils.buildUniqueFileName(new File("/dir"), "Filename", "ext");
|
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() {
|
public void testBuildUniqueFileName_exist() {
|
||||||
// Expect "/default.prop" to exist on the phone/emulator
|
// Expect "/default.prop" to exist on the phone/emulator
|
||||||
String filename = FileUtils.buildUniqueFileName(new File("/"), "default", "prop");
|
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() {
|
public void testSanitizeFileName() {
|
||||||
String name = "Swim\10ming-^across:/the/ pacific (ocean).";
|
String name = "Swim\10ming-^across:/the/ pacific (ocean).";
|
||||||
String expected = "Swim_ming-^across_the_ pacific (ocean).";
|
String expected = "Swim_ming-^across_the_ pacific (ocean).";
|
||||||
Assert.assertEquals(expected, FileUtils.sanitizeFileName(name));
|
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSanitizeFileNameWithSuffix() {
|
public void testSanitizeFileNameWithSuffix() {
|
||||||
String name = "FileName.jpeg";
|
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() {
|
public void testSanitizeFileName_i18n() {
|
||||||
String name = "您好-привет";
|
String name = "您好-привет";
|
||||||
String expected = "您好-привет";
|
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() {
|
public void testSanitizeFileName_special_characters() {
|
||||||
String name = "$%'-_@~`!(){}^#&+,;=[] ";
|
String name = "$%'-_@~`!(){}^#&+,;=[] ";
|
||||||
String expected = "$%'-_@~`!(){}^#&+,;=[] ";
|
String expected = "$%'-_@~`!(){}^#&+,;=[] ";
|
||||||
Assert.assertEquals(expected, FileUtils.sanitizeFileName(name));
|
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,7 +98,7 @@ public class FileUtilsTest {
|
|||||||
public void testSanitizeFileName_collapse() {
|
public void testSanitizeFileName_collapse() {
|
||||||
String name = "hello//there";
|
String name = "hello//there";
|
||||||
String expected = "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);
|
String truncated = FileUtils.truncateFileName(directory, nameString, suffix);
|
||||||
|
|
||||||
for (int i = 0; i < truncated.length(); i++) {
|
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.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class PreferencesUtilsTest {
|
public class PreferencesUtilsTest {
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ public class PreferencesUtilsTest {
|
|||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL, trackFileFormat);
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL, trackFileFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -43,7 +44,7 @@ public class PreferencesUtilsTest {
|
|||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -57,6 +58,6 @@ public class PreferencesUtilsTest {
|
|||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,13 +21,15 @@ import android.content.Context;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link StringUtils}.
|
* Tests for {@link StringUtils}.
|
||||||
*
|
*
|
||||||
@@ -44,7 +46,7 @@ public class StringUtilsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testFormatDateTimeIso8601() {
|
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
|
@Test
|
||||||
public void testformatElapsedTime() {
|
public void testformatElapsedTime() {
|
||||||
// 1 second
|
// 1 second
|
||||||
Assert.assertEquals("00:01", StringUtils.formatElapsedTime(1000));
|
assertEquals("00:01", StringUtils.formatElapsedTime(1000));
|
||||||
// 10 seconds
|
// 10 seconds
|
||||||
Assert.assertEquals("00:10", StringUtils.formatElapsedTime(10000));
|
assertEquals("00:10", StringUtils.formatElapsedTime(10000));
|
||||||
// 1 minute
|
// 1 minute
|
||||||
Assert.assertEquals("01:00", StringUtils.formatElapsedTime(60000));
|
assertEquals("01:00", StringUtils.formatElapsedTime(60000));
|
||||||
// 10 minutes
|
// 10 minutes
|
||||||
Assert.assertEquals("10:00", StringUtils.formatElapsedTime(600000));
|
assertEquals("10:00", StringUtils.formatElapsedTime(600000));
|
||||||
// 1 hour
|
// 1 hour
|
||||||
Assert.assertEquals("1:00:00", StringUtils.formatElapsedTime(3600000));
|
assertEquals("1:00:00", StringUtils.formatElapsedTime(3600000));
|
||||||
// 10 hours
|
// 10 hours
|
||||||
Assert.assertEquals("10:00:00", StringUtils.formatElapsedTime(36000000));
|
assertEquals("10:00:00", StringUtils.formatElapsedTime(36000000));
|
||||||
// 100 hours
|
// 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
|
@Test
|
||||||
public void testformatElapsedTimeWithHour() {
|
public void testformatElapsedTimeWithHour() {
|
||||||
// 1 second
|
// 1 second
|
||||||
Assert.assertEquals("0:00:01", StringUtils.formatElapsedTimeWithHour(1000));
|
assertEquals("0:00:01", StringUtils.formatElapsedTimeWithHour(1000));
|
||||||
// 10 seconds
|
// 10 seconds
|
||||||
Assert.assertEquals("0:00:10", StringUtils.formatElapsedTimeWithHour(10000));
|
assertEquals("0:00:10", StringUtils.formatElapsedTimeWithHour(10000));
|
||||||
// 1 minute
|
// 1 minute
|
||||||
Assert.assertEquals("0:01:00", StringUtils.formatElapsedTimeWithHour(60000));
|
assertEquals("0:01:00", StringUtils.formatElapsedTimeWithHour(60000));
|
||||||
// 10 minutes
|
// 10 minutes
|
||||||
Assert.assertEquals("0:10:00", StringUtils.formatElapsedTimeWithHour(600000));
|
assertEquals("0:10:00", StringUtils.formatElapsedTimeWithHour(600000));
|
||||||
// 1 hour
|
// 1 hour
|
||||||
Assert.assertEquals("1:00:00", StringUtils.formatElapsedTimeWithHour(3600000));
|
assertEquals("1:00:00", StringUtils.formatElapsedTimeWithHour(3600000));
|
||||||
// 10 hours
|
// 10 hours
|
||||||
Assert.assertEquals("10:00:00", StringUtils.formatElapsedTimeWithHour(36000000));
|
assertEquals("10:00:00", StringUtils.formatElapsedTimeWithHour(36000000));
|
||||||
// 100 hours
|
// 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
|
@Test
|
||||||
public void testFormatDistance() {
|
public void testFormatDistance() {
|
||||||
// A large number in metric
|
// 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
|
// 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
|
// 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
|
// 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
|
@Test
|
||||||
public void testFormatCData() {
|
public void testFormatCData() {
|
||||||
Assert.assertEquals("<![CDATA[hello]]>", StringUtils.formatCData("hello"));
|
assertEquals("<![CDATA[hello]]>", StringUtils.formatCData("hello"));
|
||||||
Assert.assertEquals("<![CDATA[hello]]]]><![CDATA[>there]]>", StringUtils.formatCData("hello]]>there"));
|
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)
|
// This comparision tends to be flaky (difference of 1ms)
|
||||||
// Assert.assertEquals(calendar.getTimeInMillis(), StringUtils.parseTime(xmlDateTime));
|
// 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
|
@Test
|
||||||
public void testGetTimeParts_positive() {
|
public void testGetTimeParts_positive() {
|
||||||
int[] parts = StringUtils.getTimeParts(61000);
|
int[] parts = StringUtils.getTimeParts(61000);
|
||||||
Assert.assertEquals(1, parts[0]);
|
assertEquals(1, parts[0]);
|
||||||
Assert.assertEquals(1, parts[1]);
|
assertEquals(1, parts[1]);
|
||||||
Assert.assertEquals(0, parts[2]);
|
assertEquals(0, parts[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,40 +190,40 @@ public class StringUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testGetTimeParts_negative() {
|
public void testGetTimeParts_negative() {
|
||||||
int[] parts = StringUtils.getTimeParts(-61000);
|
int[] parts = StringUtils.getTimeParts(-61000);
|
||||||
Assert.assertEquals(-1, parts[0]);
|
assertEquals(-1, parts[0]);
|
||||||
Assert.assertEquals(-1, parts[1]);
|
assertEquals(-1, parts[1]);
|
||||||
Assert.assertEquals(0, parts[2]);
|
assertEquals(0, parts[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFormatDecimal() {
|
public void testFormatDecimal() {
|
||||||
Assert.assertEquals("0", StringUtils.formatDecimal(0.0, 0));
|
assertEquals("0", StringUtils.formatDecimal(0.0, 0));
|
||||||
Assert.assertEquals("0", StringUtils.formatDecimal(0.1, 0));
|
assertEquals("0", StringUtils.formatDecimal(0.1, 0));
|
||||||
Assert.assertEquals("1", StringUtils.formatDecimal(1.1, 0));
|
assertEquals("1", StringUtils.formatDecimal(1.1, 0));
|
||||||
Assert.assertEquals("10", StringUtils.formatDecimal(10, 0));
|
assertEquals("10", StringUtils.formatDecimal(10, 0));
|
||||||
Assert.assertEquals("10", StringUtils.formatDecimal(10.1, 0));
|
assertEquals("10", StringUtils.formatDecimal(10.1, 0));
|
||||||
Assert.assertEquals("0", StringUtils.formatDecimal(-0.1, 0));
|
assertEquals("-0", StringUtils.formatDecimal(-0.1, 0));
|
||||||
|
|
||||||
Assert.assertEquals("0", StringUtils.formatDecimal(0.0, 2));
|
assertEquals("0", StringUtils.formatDecimal(0.0, 2));
|
||||||
Assert.assertEquals("0.1", StringUtils.formatDecimal(0.1, 2));
|
assertEquals("0.1", StringUtils.formatDecimal(0.1, 2));
|
||||||
Assert.assertEquals("1.1", StringUtils.formatDecimal(1.1, 2));
|
assertEquals("1.1", StringUtils.formatDecimal(1.1, 2));
|
||||||
Assert.assertEquals("10", StringUtils.formatDecimal(10, 2));
|
assertEquals("10", StringUtils.formatDecimal(10, 2));
|
||||||
Assert.assertEquals("10.1", StringUtils.formatDecimal(10.1, 2));
|
assertEquals("10.1", StringUtils.formatDecimal(10.1, 2));
|
||||||
Assert.assertEquals("10.11", StringUtils.formatDecimal(10.111, 2));
|
assertEquals("10.11", StringUtils.formatDecimal(10.111, 2));
|
||||||
Assert.assertEquals("-0.1", StringUtils.formatDecimal(-0.1, 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
|
@Test
|
||||||
public void testGetSpeedParts() {
|
public void testGetSpeedParts() {
|
||||||
Assert.assertEquals("4:59", StringUtils.getSpeedParts(context, 3.34, true, false).first);
|
assertEquals("4:59", StringUtils.getSpeedParts(context, 3.34, true, false).first);
|
||||||
Assert.assertEquals("5:00", StringUtils.getSpeedParts(context, 3.33, 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);
|
assertEquals("11.9", StringUtils.getSpeedParts(context, 3.31, true, true).first);
|
||||||
Assert.assertEquals("7.45", StringUtils.getSpeedParts(context, 3.33, false, true).first);
|
assertEquals("7.5", StringUtils.getSpeedParts(context, 3.34, false, true).first);
|
||||||
|
|
||||||
Assert.assertEquals("min/km", StringUtils.getSpeedParts(context, 0, true, false).second);
|
assertEquals("min/km", StringUtils.getSpeedParts(context, 0, true, false).second);
|
||||||
Assert.assertEquals("min/mi", StringUtils.getSpeedParts(context, 0, false, 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.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
@@ -30,6 +29,9 @@ import java.util.Date;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link TrackNameUtils}.
|
* Tests {@link TrackNameUtils}.
|
||||||
@@ -39,7 +41,7 @@ import de.dennisguse.opentracks.R;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class TrackNameUtilsTest {
|
public class TrackNameUtilsTest {
|
||||||
|
|
||||||
private static final long TRACK_ID = 1L;
|
private static final Track.Id TRACK_ID = new Track.Id(1L);
|
||||||
private static final long START_TIME = 1288213406000L;
|
private static final long START_TIME = 1288213406000L;
|
||||||
|
|
||||||
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
|
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
|
||||||
@@ -50,7 +52,7 @@ public class TrackNameUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testTrackName_date_local() {
|
public void testTrackName_date_local() {
|
||||||
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_local_value));
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +62,7 @@ public class TrackNameUtilsTest {
|
|||||||
public void testTrackName_date_iso_8601() {
|
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));
|
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);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,6 +71,6 @@ public class TrackNameUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testTrackName_number() {
|
public void testTrackName_number() {
|
||||||
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_number_value));
|
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_number_value));
|
||||||
Assert.assertEquals("Track " + TRACK_ID, 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;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
public class TrackPointUtilsTest {
|
public class TrackPointUtilsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -18,7 +19,7 @@ public class TrackPointUtilsTest {
|
|||||||
TrackPointUtils.fixTime(trackPoint);
|
TrackPointUtils.fixTime(trackPoint);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(time, trackPoint.getTime());
|
assertEquals(time, trackPoint.getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -32,7 +33,7 @@ public class TrackPointUtilsTest {
|
|||||||
TrackPointUtils.fixTime(trackPoint);
|
TrackPointUtils.fixTime(trackPoint);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(time, trackPoint.getTime(), 1000);
|
assertEquals(time, trackPoint.getTime(), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -46,7 +47,7 @@ public class TrackPointUtilsTest {
|
|||||||
TrackPointUtils.fixTime(trackPoint);
|
TrackPointUtils.fixTime(trackPoint);
|
||||||
|
|
||||||
// then
|
// 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 androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class UUIDUtilsTest {
|
public class UUIDUtilsTest {
|
||||||
|
|
||||||
@@ -18,6 +19,6 @@ public class UUIDUtilsTest {
|
|||||||
byte[] bytes = UUIDUtils.toBytes(uuid);
|
byte[] bytes = UUIDUtils.toBytes(uuid);
|
||||||
UUID output = UUIDUtils.fromBytes(bytes);
|
UUID output = UUIDUtils.fromBytes(bytes);
|
||||||
|
|
||||||
Assert.assertEquals(uuid, output);
|
assertEquals(uuid, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+45
-43
@@ -4,7 +4,6 @@ import android.content.Context;
|
|||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
@@ -14,6 +13,9 @@ import de.dennisguse.opentracks.content.data.Track;
|
|||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class AggregatedStatisticsTest {
|
public class AggregatedStatisticsTest {
|
||||||
|
|
||||||
@@ -59,13 +61,13 @@ public class AggregatedStatisticsTest {
|
|||||||
aggregatedStatistics.aggregate(track);
|
aggregatedStatistics.aggregate(track);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(1, aggregatedStatistics.getCount());
|
assertEquals(1, aggregatedStatistics.getCount());
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(biking));
|
assertNotNull(aggregatedStatistics.get(biking));
|
||||||
Assert.assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
||||||
|
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
assertEquals(totalTime, statistics2.getMovingTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -82,7 +84,7 @@ public class AggregatedStatisticsTest {
|
|||||||
aggregatedStatistics.aggregate(track);
|
aggregatedStatistics.aggregate(track);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(mountainBiking));
|
assertNotNull(aggregatedStatistics.get(mountainBiking));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -99,7 +101,7 @@ public class AggregatedStatisticsTest {
|
|||||||
aggregatedStatistics.aggregate(track);
|
aggregatedStatistics.aggregate(track);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(trailRunning));
|
assertNotNull(aggregatedStatistics.get(trailRunning));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -120,13 +122,13 @@ public class AggregatedStatisticsTest {
|
|||||||
aggregatedStatistics.aggregate(tracks[1]); // biking activity 2.
|
aggregatedStatistics.aggregate(tracks[1]); // biking activity 2.
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(1, aggregatedStatistics.getCount());
|
assertEquals(1, aggregatedStatistics.getCount());
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(biking));
|
assertNotNull(aggregatedStatistics.get(biking));
|
||||||
Assert.assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
|
assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
|
||||||
|
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime * 2L, statistics2.getMovingTime());
|
assertEquals(totalTime * 2L, statistics2.getMovingTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -152,30 +154,30 @@ public class AggregatedStatisticsTest {
|
|||||||
aggregatedStatistics.aggregate(tracks[2]); // biking activity 3.
|
aggregatedStatistics.aggregate(tracks[2]); // biking activity 3.
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(3, aggregatedStatistics.getCount());
|
assertEquals(3, aggregatedStatistics.getCount());
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(biking));
|
assertNotNull(aggregatedStatistics.get(biking));
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(running));
|
assertNotNull(aggregatedStatistics.get(running));
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(walking));
|
assertNotNull(aggregatedStatistics.get(walking));
|
||||||
Assert.assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
|
||||||
Assert.assertEquals(1, aggregatedStatistics.get(running).getCountTracks());
|
assertEquals(1, aggregatedStatistics.get(running).getCountTracks());
|
||||||
Assert.assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
|
assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
|
||||||
|
|
||||||
{
|
{
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
assertEquals(totalTime, statistics2.getMovingTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
assertEquals(totalTime, statistics2.getMovingTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
assertEquals(totalTime, statistics2.getMovingTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,46 +214,46 @@ public class AggregatedStatisticsTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
// 4 sports.
|
// 4 sports.
|
||||||
Assert.assertEquals(4, aggregatedStatistics.getCount());
|
assertEquals(4, aggregatedStatistics.getCount());
|
||||||
|
|
||||||
// There is a map for every sport.
|
// There is a map for every sport.
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(biking));
|
assertNotNull(aggregatedStatistics.get(biking));
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(running));
|
assertNotNull(aggregatedStatistics.get(running));
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(walking));
|
assertNotNull(aggregatedStatistics.get(walking));
|
||||||
Assert.assertNotNull(aggregatedStatistics.get(driving));
|
assertNotNull(aggregatedStatistics.get(driving));
|
||||||
|
|
||||||
// Number of tracks by sport.
|
// Number of tracks by sport.
|
||||||
Assert.assertEquals(5, aggregatedStatistics.get(biking).getCountTracks()); // Biking.
|
assertEquals(5, aggregatedStatistics.get(biking).getCountTracks()); // Biking.
|
||||||
Assert.assertEquals(2, aggregatedStatistics.get(running).getCountTracks()); // Running.
|
assertEquals(2, aggregatedStatistics.get(running).getCountTracks()); // Running.
|
||||||
Assert.assertEquals(2, aggregatedStatistics.get(walking).getCountTracks()); // Walking.
|
assertEquals(2, aggregatedStatistics.get(walking).getCountTracks()); // Walking.
|
||||||
Assert.assertEquals(1, aggregatedStatistics.get(driving).getCountTracks()); // Driving.
|
assertEquals(1, aggregatedStatistics.get(driving).getCountTracks()); // Driving.
|
||||||
|
|
||||||
// Biking.
|
// Biking.
|
||||||
{
|
{
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance * 5, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance * 5, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime * 5, statistics2.getMovingTime());
|
assertEquals(totalTime * 5, statistics2.getMovingTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Running.
|
// Running.
|
||||||
{
|
{
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime * 2, statistics2.getMovingTime());
|
assertEquals(totalTime * 2, statistics2.getMovingTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walking.
|
// Walking.
|
||||||
{
|
{
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime * 2, statistics2.getMovingTime());
|
assertEquals(totalTime * 2, statistics2.getMovingTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Driving.
|
// Driving.
|
||||||
{
|
{
|
||||||
TrackStatistics statistics2 = aggregatedStatistics.get(driving).getTrackStatistics();
|
TrackStatistics statistics2 = aggregatedStatistics.get(driving).getTrackStatistics();
|
||||||
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
|
||||||
Assert.assertEquals(totalTime, statistics2.getMovingTime());
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,10 @@ package de.dennisguse.opentracks;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
||||||
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment.ConfirmDeleteCaller;
|
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment.ConfirmDeleteCaller;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||||
@@ -55,17 +59,17 @@ public abstract class AbstractListActivity extends AbstractActivity implements C
|
|||||||
*
|
*
|
||||||
* @param trackIds the track ids
|
* @param trackIds the track ids
|
||||||
*/
|
*/
|
||||||
protected void deleteTracks(long[] trackIds) {
|
protected void deleteTracks(Track.Id... trackIds) {
|
||||||
ConfirmDeleteDialogFragment.showDialog(getSupportFragmentManager(), trackIds);
|
ConfirmDeleteDialogFragment.showDialog(getSupportFragmentManager(), trackIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfirmDeleteDone(long[] trackIds) {
|
public void onConfirmDeleteDone(Track.Id... trackIds) {
|
||||||
boolean stopRecording = false;
|
boolean stopRecording = false;
|
||||||
|
|
||||||
long recordingTrackId = PreferencesUtils.getRecordingTrackId(this);
|
Track.Id recordingTrackId = PreferencesUtils.getRecordingTrackId(this);
|
||||||
for (long trackId : trackIds) {
|
for (Track.Id trackId : trackIds) {
|
||||||
if (trackId == recordingTrackId) {
|
if (trackId.equals(recordingTrackId)) {
|
||||||
stopRecording = true;
|
stopRecording = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -75,7 +79,7 @@ public abstract class AbstractListActivity extends AbstractActivity implements C
|
|||||||
getTrackRecordingServiceConnection().stopRecording(this, false);
|
getTrackRecordingServiceConnection().stopRecording(this, false);
|
||||||
}
|
}
|
||||||
Intent intent = IntentUtils.newIntent(this, TrackDeleteActivity.class);
|
Intent intent = IntentUtils.newIntent(this, TrackDeleteActivity.class);
|
||||||
intent.putExtra(TrackDeleteActivity.EXTRA_TRACK_IDS, trackIds);
|
intent.putParcelableArrayListExtra(TrackDeleteActivity.EXTRA_TRACK_IDS, new ArrayList<>(Arrays.asList(trackIds)));
|
||||||
startActivityForResult(intent, DELETE_REQUEST_CODE);
|
startActivityForResult(intent, DELETE_REQUEST_CODE);
|
||||||
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
|
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import androidx.viewpager.widget.ViewPager;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
|
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
|
||||||
import de.dennisguse.opentracks.fragments.MarkerDetailFragment;
|
import de.dennisguse.opentracks.fragments.MarkerDetailFragment;
|
||||||
@@ -48,32 +48,33 @@ public class MarkerDetailActivity extends AbstractActivity implements DeleteMark
|
|||||||
|
|
||||||
private static final String TAG = MarkerDetailActivity.class.getSimpleName();
|
private static final String TAG = MarkerDetailActivity.class.getSimpleName();
|
||||||
|
|
||||||
private List<Long> markerIds;
|
private List<Marker.Id> waypointIds;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle bundle) {
|
protected void onCreate(Bundle bundle) {
|
||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
|
|
||||||
long markerId = getIntent().getLongExtra(EXTRA_MARKER_ID, -1L);
|
Marker.Id waypointId = getIntent().getParcelableExtra(EXTRA_MARKER_ID);
|
||||||
if (markerId == -1L) {
|
if (waypointId == null) {
|
||||||
Log.d(TAG, "invalid marker id");
|
Log.d(TAG, "invalid marker id");
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
||||||
Waypoint waypoint = contentProviderUtils.getWaypoint(markerId);
|
Marker waypoint = contentProviderUtils.getMarker(waypointId);
|
||||||
|
|
||||||
markerIds = new ArrayList<>();
|
waypointIds = new ArrayList<>();
|
||||||
int markerIndex = -1;
|
int markerIndex = -1;
|
||||||
|
|
||||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(waypoint.getTrackId(), -1L, -1)) {
|
//TODO Load only waypointIds, not the whole waypoint
|
||||||
|
try (Cursor cursor = contentProviderUtils.getMarkerCursor(waypoint.getTrackId(), null, -1)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
for (int i = 0; i < cursor.getCount(); i++) {
|
for (int i = 0; i < cursor.getCount(); i++) {
|
||||||
Waypoint currentMarker = contentProviderUtils.createWaypoint(cursor);
|
Marker currentMarker = contentProviderUtils.createMarker(cursor);
|
||||||
markerIds.add(currentMarker.getId());
|
waypointIds.add(currentMarker.getId());
|
||||||
if (currentMarker.getId() == markerId) {
|
if (waypointId.equals(currentMarker.getId())) {
|
||||||
markerIndex = markerIds.size() - 1;
|
markerIndex = waypointIds.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor.moveToNext();
|
cursor.moveToNext();
|
||||||
@@ -126,7 +127,7 @@ public class MarkerDetailActivity extends AbstractActivity implements DeleteMark
|
|||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public Fragment getItem(int position) {
|
public Fragment getItem(int position) {
|
||||||
return MarkerDetailFragment.newInstance(markerIds.get(position));
|
return MarkerDetailFragment.newInstance(waypointIds.get(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -137,7 +138,7 @@ public class MarkerDetailActivity extends AbstractActivity implements DeleteMark
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return markerIds.size();
|
return waypointIds.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,8 @@ import java.io.File;
|
|||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
@@ -64,9 +65,9 @@ public class MarkerEditActivity extends AbstractActivity {
|
|||||||
private static final int GALLERY_IMG_REQUEST_CODE = 7;
|
private static final int GALLERY_IMG_REQUEST_CODE = 7;
|
||||||
|
|
||||||
private static final String TAG = MarkerEditActivity.class.getSimpleName();
|
private static final String TAG = MarkerEditActivity.class.getSimpleName();
|
||||||
private long trackId;
|
private Track.Id trackId;
|
||||||
private TrackRecordingServiceConnection trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
private TrackRecordingServiceConnection trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
||||||
private Waypoint waypoint;
|
private Marker waypoint;
|
||||||
|
|
||||||
private MenuItem insertPhotoMenuItem;
|
private MenuItem insertPhotoMenuItem;
|
||||||
private MenuItem insertGalleryImgMenuItem;
|
private MenuItem insertGalleryImgMenuItem;
|
||||||
@@ -85,8 +86,8 @@ public class MarkerEditActivity extends AbstractActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
trackId = getIntent().getLongExtra(EXTRA_TRACK_ID, -1L);
|
trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID);
|
||||||
long markerId = getIntent().getLongExtra(EXTRA_MARKER_ID, -1L);
|
Marker.Id waypointId = getIntent().getParcelableExtra(EXTRA_MARKER_ID);
|
||||||
|
|
||||||
hasCamera = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
|
hasCamera = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
|
||||||
|
|
||||||
@@ -111,7 +112,7 @@ public class MarkerEditActivity extends AbstractActivity {
|
|||||||
Button cancel = findViewById(R.id.marker_edit_cancel);
|
Button cancel = findViewById(R.id.marker_edit_cancel);
|
||||||
cancel.setOnClickListener(v -> finish());
|
cancel.setOnClickListener(v -> finish());
|
||||||
|
|
||||||
final boolean isNewMarker = markerId == -1L;
|
final boolean isNewMarker = waypointId == null;
|
||||||
|
|
||||||
setTitle(isNewMarker ? R.string.menu_insert_marker : R.string.menu_edit);
|
setTitle(isNewMarker ? R.string.menu_insert_marker : R.string.menu_edit);
|
||||||
Button done = findViewById(R.id.marker_edit_done);
|
Button done = findViewById(R.id.marker_edit_done);
|
||||||
@@ -126,7 +127,7 @@ public class MarkerEditActivity extends AbstractActivity {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isNewMarker) {
|
if (isNewMarker) {
|
||||||
int nextWaypointNumber = trackId == -1L ? -1 : new ContentProviderUtils(this).getNextWaypointNumber(trackId);
|
int nextWaypointNumber = trackId == null ? -1 : new ContentProviderUtils(this).getNextMarkerNumber(trackId);
|
||||||
if (nextWaypointNumber == -1) {
|
if (nextWaypointNumber == -1) {
|
||||||
nextWaypointNumber = 0;
|
nextWaypointNumber = 0;
|
||||||
}
|
}
|
||||||
@@ -135,7 +136,7 @@ public class MarkerEditActivity extends AbstractActivity {
|
|||||||
waypointMarkerType.setText("");
|
waypointMarkerType.setText("");
|
||||||
waypointDescription.setText("");
|
waypointDescription.setText("");
|
||||||
} else {
|
} else {
|
||||||
waypoint = new ContentProviderUtils(this).getWaypoint(markerId);
|
waypoint = new ContentProviderUtils(this).getMarker(waypointId);
|
||||||
if (waypoint == null) {
|
if (waypoint == null) {
|
||||||
Log.d(TAG, "waypoint is null");
|
Log.d(TAG, "waypoint is null");
|
||||||
finish();
|
finish();
|
||||||
@@ -260,8 +261,8 @@ public class MarkerEditActivity extends AbstractActivity {
|
|||||||
/**
|
/**
|
||||||
* Returns the trackId. If trackId == -1 then get it from waypoint object.
|
* Returns the trackId. If trackId == -1 then get it from waypoint object.
|
||||||
*/
|
*/
|
||||||
private long getTrackId() {
|
private Track.Id getTrackId() {
|
||||||
return trackId == -1 ? waypoint.getTrackId() : trackId;
|
return trackId == null ? waypoint.getTrackId() : trackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -306,6 +307,6 @@ public class MarkerEditActivity extends AbstractActivity {
|
|||||||
waypoint.setDescription(waypointDescription.getText().toString());
|
waypoint.setDescription(waypointDescription.getText().toString());
|
||||||
waypoint.setPhotoUrl(photoUri != null ? photoUri.toString() : null);
|
waypoint.setPhotoUrl(photoUri != null ? photoUri.toString() : null);
|
||||||
|
|
||||||
new ContentProviderUtils(this).updateWaypoint(this, waypoint);
|
new ContentProviderUtils(this).updateMarker(this, waypoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.cursoradapter.widget.ResourceCursorAdapter;
|
import androidx.cursoradapter.widget.ResourceCursorAdapter;
|
||||||
import androidx.loader.app.LoaderManager;
|
import androidx.loader.app.LoaderManager;
|
||||||
import androidx.loader.app.LoaderManager.LoaderCallbacks;
|
import androidx.loader.app.LoaderManager.LoaderCallbacks;
|
||||||
import androidx.loader.content.CursorLoader;
|
|
||||||
import androidx.loader.content.Loader;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
|
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
|
||||||
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
|
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
|
||||||
@@ -57,16 +57,11 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
|
|
||||||
private static final String TAG = MarkerListActivity.class.getSimpleName();
|
private static final String TAG = MarkerListActivity.class.getSimpleName();
|
||||||
|
|
||||||
private static final String[] PROJECTION = new String[]{WaypointsColumns._ID,
|
|
||||||
WaypointsColumns.NAME, WaypointsColumns.DESCRIPTION, WaypointsColumns.CATEGORY,
|
|
||||||
WaypointsColumns.TIME, WaypointsColumns.PHOTOURL,
|
|
||||||
WaypointsColumns.LATITUDE, WaypointsColumns.LONGITUDE};
|
|
||||||
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
private SharedPreferences sharedPreferences;
|
private SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
private Track.Id recordingTrackId;
|
||||||
private boolean recordingTrackPaused;
|
private boolean recordingTrackPaused;
|
||||||
|
|
||||||
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
@@ -117,31 +112,31 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
|
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
|
||||||
long trackId = getIntent().getLongExtra(EXTRA_TRACK_ID, -1L);
|
Track.Id trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID);
|
||||||
recordingTrackPaused = PreferencesUtils.isRecordingTrackPausedDefault(this);
|
recordingTrackPaused = PreferencesUtils.isRecordingTrackPausedDefault(this);
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(this);
|
contentProviderUtils = new ContentProviderUtils(this);
|
||||||
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
|
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
|
||||||
|
|
||||||
track = trackId != -1L ? contentProviderUtils.getTrack(trackId) : null;
|
track = trackId != null ? contentProviderUtils.getTrack(trackId) : null;
|
||||||
|
|
||||||
listView = findViewById(R.id.marker_list);
|
listView = findViewById(R.id.marker_list);
|
||||||
listView.setEmptyView(findViewById(R.id.marker_list_empty));
|
listView.setEmptyView(findViewById(R.id.marker_list_empty));
|
||||||
listView.setOnItemClickListener((parent, view, position, id) -> {
|
listView.setOnItemClickListener((parent, view, position, id) -> {
|
||||||
Intent intent = IntentUtils.newIntent(MarkerListActivity.this, MarkerDetailActivity.class)
|
Intent intent = IntentUtils.newIntent(MarkerListActivity.this, MarkerDetailActivity.class)
|
||||||
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, id);
|
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, new Marker.Id(id));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
});
|
});
|
||||||
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) {
|
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) {
|
||||||
@Override
|
@Override
|
||||||
public void bindView(View view, Context context, Cursor cursor) {
|
public void bindView(View view, Context context, Cursor cursor) {
|
||||||
int nameIndex = cursor.getColumnIndex(WaypointsColumns.NAME);
|
int nameIndex = cursor.getColumnIndex(MarkerColumns.NAME);
|
||||||
int timeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.TIME);
|
int timeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.TIME);
|
||||||
int categoryIndex = cursor.getColumnIndex(WaypointsColumns.CATEGORY);
|
int categoryIndex = cursor.getColumnIndex(MarkerColumns.CATEGORY);
|
||||||
int descriptionIndex = cursor.getColumnIndex(WaypointsColumns.DESCRIPTION);
|
int descriptionIndex = cursor.getColumnIndex(MarkerColumns.DESCRIPTION);
|
||||||
int photoUrlIndex = cursor.getColumnIndex(WaypointsColumns.PHOTOURL);
|
int photoUrlIndex = cursor.getColumnIndex(MarkerColumns.PHOTOURL);
|
||||||
int latitudeIndex = cursor.getColumnIndex(WaypointsColumns.LATITUDE);
|
int latitudeIndex = cursor.getColumnIndex(MarkerColumns.LATITUDE);
|
||||||
int longitudeIndex = cursor.getColumnIndex(WaypointsColumns.LONGITUDE);
|
int longitudeIndex = cursor.getColumnIndex(MarkerColumns.LONGITUDE);
|
||||||
|
|
||||||
int iconId = MarkerUtils.ICON_ID;
|
int iconId = MarkerUtils.ICON_ID;
|
||||||
String name = cursor.getString(nameIndex);
|
String name = cursor.getString(nameIndex);
|
||||||
@@ -163,14 +158,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||||
if (track != null) {
|
return ContentProviderUtils.getMarkersLoader(MarkerListActivity.this, track != null ? track.getId() : null);
|
||||||
return new CursorLoader(MarkerListActivity.this, WaypointsColumns.CONTENT_URI, PROJECTION,
|
|
||||||
WaypointsColumns.TRACKID + "=?",
|
|
||||||
new String[]{String.valueOf(track.getId())}, null);
|
|
||||||
} else {
|
|
||||||
return new CursorLoader(MarkerListActivity.this, WaypointsColumns.CONTENT_URI, PROJECTION,
|
|
||||||
null, null, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -223,7 +211,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
insertMarkerMenuItem.setVisible(track != null && track.getId() == recordingTrackId && !recordingTrackPaused);
|
insertMarkerMenuItem.setVisible(track != null && track.getId().equals(recordingTrackId) && !recordingTrackPaused);
|
||||||
return super.onPrepareOptionsMenu(menu);
|
return super.onPrepareOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,30 +229,35 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
/**
|
/**
|
||||||
* Handles a context item selection.
|
* Handles a context item selection.
|
||||||
*
|
*
|
||||||
* @param itemId the menu item id
|
* @param itemId the menu item id
|
||||||
* @param markerIds the marker ids
|
* @param longWaypointIds the marker ids
|
||||||
* @return true if handled.
|
* @return true if handled.
|
||||||
*/
|
*/
|
||||||
private boolean handleContextItem(int itemId, long[] markerIds) {
|
private boolean handleContextItem(int itemId, long... longWaypointIds) {
|
||||||
|
Marker.Id[] waypointIds = new Marker.Id[longWaypointIds.length];
|
||||||
|
for (int i = 0; i < longWaypointIds.length; i++) {
|
||||||
|
waypointIds[i] = new Marker.Id(longWaypointIds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
Intent intent;
|
Intent intent;
|
||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case R.id.list_context_menu_show_on_map:
|
case R.id.list_context_menu_show_on_map:
|
||||||
if (markerIds.length == 1) {
|
if (waypointIds.length == 1) {
|
||||||
IntentUtils.showCoordinateOnMap(this, contentProviderUtils.getWaypoint(markerIds[0]));
|
IntentUtils.showCoordinateOnMap(this, contentProviderUtils.getMarker(waypointIds[0]));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case R.id.list_context_menu_edit:
|
case R.id.list_context_menu_edit:
|
||||||
if (markerIds.length == 1) {
|
if (waypointIds.length == 1) {
|
||||||
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
|
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
|
||||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerIds[0]);
|
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, waypointIds[0]);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case R.id.list_context_menu_delete:
|
case R.id.list_context_menu_delete:
|
||||||
if (markerIds.length > 1 && markerIds.length == listView.getCount()) {
|
if (waypointIds.length > 1 && waypointIds.length == listView.getCount()) {
|
||||||
markerIds = new long[]{-1L};
|
waypointIds = null;
|
||||||
}
|
}
|
||||||
DeleteMarkerDialogFragment.showDialog(getSupportFragmentManager(), markerIds);
|
DeleteMarkerDialogFragment.showDialog(getSupportFragmentManager(), waypointIds);
|
||||||
return true;
|
return true;
|
||||||
case R.id.list_context_menu_select_all:
|
case R.id.list_context_menu_select_all:
|
||||||
for (int i = 0; i < listView.getCount(); i++) {
|
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;
|
||||||
import de.dennisguse.opentracks.content.SearchEngine.ScoredResult;
|
import de.dennisguse.opentracks.content.SearchEngine.ScoredResult;
|
||||||
import de.dennisguse.opentracks.content.SearchEngine.SearchQuery;
|
import de.dennisguse.opentracks.content.SearchEngine.SearchQuery;
|
||||||
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
||||||
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
|
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
|
||||||
@@ -97,7 +97,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
|
|
||||||
private boolean metricUnits = true;
|
private boolean metricUnits = true;
|
||||||
|
|
||||||
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
private Track.Id recordingTrackId;
|
||||||
|
|
||||||
private boolean recordingTrackPaused;
|
private boolean recordingTrackPaused;
|
||||||
|
|
||||||
@@ -203,8 +203,8 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
listView.setEmptyView(findViewById(R.id.search_list_empty));
|
listView.setEmptyView(findViewById(R.id.search_list_empty));
|
||||||
listView.setOnItemClickListener((parent, view, position, id) -> {
|
listView.setOnItemClickListener((parent, view, position, id) -> {
|
||||||
Map<String, Object> item = arrayAdapter.getItem(position);
|
Map<String, Object> item = arrayAdapter.getItem(position);
|
||||||
Long trackId = (Long) item.get(TRACK_ID_FIELD);
|
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);
|
Intent intent = IntentUtils.newIntent(SearchListActivity.this, TrackRecordedActivity.class);
|
||||||
if (markerId != null) {
|
if (markerId != null) {
|
||||||
intent = intent.putExtra(TrackRecordedActivity.EXTRA_MARKER_ID, markerId);
|
intent = intent.putExtra(TrackRecordedActivity.EXTRA_MARKER_ID, markerId);
|
||||||
@@ -270,22 +270,22 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Map<String, Object> item = arrayAdapter.getItem(positions[0]);
|
Map<String, Object> item = arrayAdapter.getItem(positions[0]);
|
||||||
Long trackId = (Long) item.get(TRACK_ID_FIELD);
|
Track.Id trackId = (Track.Id) item.get(TRACK_ID_FIELD);
|
||||||
Long markerId = (Long) item.get(MARKER_ID_FIELD);
|
Marker.Id waypointId = (Marker.Id) item.get(MARKER_ID_FIELD);
|
||||||
Intent intent;
|
Intent intent;
|
||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case R.id.list_context_menu_show_on_map:
|
case R.id.list_context_menu_show_on_map:
|
||||||
IntentUtils.showCoordinateOnMap(this, (double) item.get(MARKER_LATITUDE_FIELD), (double) item.get(MARKER_LONGITUDE_FIELD), item.get(NAME_FIELD) + "");
|
IntentUtils.showCoordinateOnMap(this, (double) item.get(MARKER_LATITUDE_FIELD), (double) item.get(MARKER_LONGITUDE_FIELD), item.get(NAME_FIELD) + "");
|
||||||
return true;
|
return true;
|
||||||
case R.id.list_context_menu_share:
|
case R.id.list_context_menu_share:
|
||||||
intent = IntentUtils.newShareFileIntent(this, new long[]{trackId});
|
intent = IntentUtils.newShareFileIntent(this, trackId);
|
||||||
intent = Intent.createChooser(intent, null);
|
intent = Intent.createChooser(intent, null);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.list_context_menu_edit:
|
case R.id.list_context_menu_edit:
|
||||||
if (markerId != null) {
|
if (waypointId != null) {
|
||||||
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
|
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
|
||||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
|
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, waypointId);
|
||||||
} else {
|
} else {
|
||||||
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
|
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
|
||||||
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
|
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
|
||||||
@@ -296,10 +296,10 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
case R.id.list_context_menu_delete:
|
case R.id.list_context_menu_delete:
|
||||||
if (markerId != null) {
|
if (waypointId != null) {
|
||||||
DeleteMarkerDialogFragment.showDialog(getSupportFragmentManager(), new long[]{markerId});
|
DeleteMarkerDialogFragment.showDialog(getSupportFragmentManager(), waypointId);
|
||||||
} else {
|
} else {
|
||||||
deleteTracks(new long[]{trackId});
|
deleteTracks(trackId);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
@@ -331,7 +331,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
* @param textQuery the query
|
* @param textQuery the query
|
||||||
*/
|
*/
|
||||||
private void doSearch(String textQuery) {
|
private void doSearch(String textQuery) {
|
||||||
SearchQuery query = new SearchQuery(textQuery, null, -1L, System.currentTimeMillis());
|
SearchQuery query = new SearchQuery(textQuery, null, null, System.currentTimeMillis());
|
||||||
SortedSet<ScoredResult> scoredResults = searchEngine.search(query);
|
SortedSet<ScoredResult> scoredResults = searchEngine.search(query);
|
||||||
final List<Map<String, Object>> displayResults = prepareResultsforDisplay(scoredResults);
|
final List<Map<String, Object>> displayResults = prepareResultsforDisplay(scoredResults);
|
||||||
|
|
||||||
@@ -355,7 +355,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
if (result.track != null) {
|
if (result.track != null) {
|
||||||
output.add(prepareTrackForDisplay(result.track));
|
output.add(prepareTrackForDisplay(result.track));
|
||||||
} else {
|
} else {
|
||||||
output.add(prepareMarkerForDisplay(result.waypoint));
|
output.add(prepareMarkerForDisplay(result.marker));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
@@ -367,13 +367,13 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
* @param waypoint the marker
|
* @param waypoint the marker
|
||||||
* @return the result map
|
* @return the result map
|
||||||
*/
|
*/
|
||||||
private Map<String, Object> prepareMarkerForDisplay(Waypoint waypoint) {
|
private Map<String, Object> prepareMarkerForDisplay(Marker waypoint) {
|
||||||
Map<String, Object> resultMap = new HashMap<>();
|
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.
|
//TODO: It may be more appropriate to obtain the track name as a join in the retrieval phase of the searchable.
|
||||||
String trackName = null;
|
String trackName = null;
|
||||||
long trackId = waypoint.getTrackId();
|
Track.Id trackId = waypoint.getTrackId();
|
||||||
if (trackId != -1L) {
|
if (!trackId.isValid()) {
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
if (track != null) {
|
if (track != null) {
|
||||||
trackName = track.getName();
|
trackName = track.getName();
|
||||||
@@ -422,7 +422,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
resultMap.put(NAME_FIELD, track.getName());
|
resultMap.put(NAME_FIELD, track.getName());
|
||||||
resultMap.put(TOTAL_TIME_FIELD, StringUtils.formatElapsedTime(trackStatistics.getTotalTime()));
|
resultMap.put(TOTAL_TIME_FIELD, StringUtils.formatElapsedTime(trackStatistics.getTotalTime()));
|
||||||
resultMap.put(TOTAL_DISTANCE_FIELD, StringUtils.formatDistance(this, trackStatistics.getTotalDistance(), metricUnits));
|
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(START_TIME_FIELD, trackStatistics.getStartTime_ms());
|
||||||
resultMap.put(CATEGORY_FIELD, category);
|
resultMap.put(CATEGORY_FIELD, category);
|
||||||
resultMap.put(DESCRIPTION_FIELD, track.getDescription());
|
resultMap.put(DESCRIPTION_FIELD, track.getDescription());
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import android.util.Pair;
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.provider.ShareContentProvider;
|
import de.dennisguse.opentracks.content.provider.ShareContentProvider;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
import de.dennisguse.opentracks.util.IntentDashboardUtils;
|
import de.dennisguse.opentracks.util.IntentDashboardUtils;
|
||||||
@@ -26,9 +28,9 @@ public abstract class ShowOnMapProxyActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
long[] trackIds = IntentDashboardUtils.extractTrackIdsFromIntent(getIntent());
|
Set<Track.Id> trackIds = IntentDashboardUtils.extractTrackIdsFromIntent(getIntent());
|
||||||
|
|
||||||
showTrackTrackfileFormat(this, trackFileFormat, trackIds);
|
showTrackfileFormat(this, trackFileFormat, trackIds);
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
@@ -39,14 +41,14 @@ public abstract class ShowOnMapProxyActivity extends AppCompatActivity {
|
|||||||
* @param context the context
|
* @param context the context
|
||||||
* @param trackIds the track ids
|
* @param trackIds the track ids
|
||||||
*/
|
*/
|
||||||
private static void showTrackTrackfileFormat(Context context, TrackFileFormat trackFileFormat, long[] trackIds) {
|
private static void showTrackfileFormat(Context context, TrackFileFormat trackFileFormat, Set<Track.Id> trackIds) {
|
||||||
if (trackIds.length == 0) {
|
if (trackIds.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
|
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.putExtra(TrackPointsColumns.TRACKID, trackIds[0]);
|
|
||||||
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, "SharingTrack", trackFileFormat);
|
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, "SharingTrack", trackFileFormat);
|
||||||
intent.setDataAndType(uriAndMime.first, uriAndMime.second);
|
intent.setDataAndType(uriAndMime.first, uriAndMime.second);
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ public class Startup extends Application {
|
|||||||
PreferencesUtils.setString(this, R.string.stats_units_key, statsUnits);
|
PreferencesUtils.setString(this, R.string.stats_units_key, statsUnits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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.");
|
||||||
|
PreferencesUtils.setLong(this, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
//In debug builds: show thread and VM warnings.
|
//In debug builds: show thread and VM warnings.
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package de.dennisguse.opentracks;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
@@ -28,6 +29,8 @@ import android.widget.ImageButton;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
|
||||||
import de.dennisguse.opentracks.util.ActivityUtils;
|
import de.dennisguse.opentracks.util.ActivityUtils;
|
||||||
@@ -134,7 +137,7 @@ public class TrackController {
|
|||||||
private final Activity activity;
|
private final Activity activity;
|
||||||
private final OnClickListener clickListener;
|
private final OnClickListener clickListener;
|
||||||
private final int delayMillis;
|
private final int delayMillis;
|
||||||
private final AnimatedVectorDrawable animatedDrawable;
|
private final Drawable drawable;
|
||||||
private final int delayMessageId;
|
private final int delayMessageId;
|
||||||
|
|
||||||
private ButtonDelay(final Activity activity, final ImageButton imageButton, final int animDrawableId, final int delayMessageId, final OnClickListener clickListener) {
|
private ButtonDelay(final Activity activity, final ImageButton imageButton, final int animDrawableId, final int delayMessageId, final OnClickListener clickListener) {
|
||||||
@@ -142,24 +145,30 @@ public class TrackController {
|
|||||||
this.clickListener = clickListener;
|
this.clickListener = clickListener;
|
||||||
this.delayMillis = activity.getResources().getInteger(R.integer.buttonDelayMillis);
|
this.delayMillis = activity.getResources().getInteger(R.integer.buttonDelayMillis);
|
||||||
this.imageButton = imageButton;
|
this.imageButton = imageButton;
|
||||||
this.animatedDrawable = (AnimatedVectorDrawable) activity.getDrawable(animDrawableId);
|
this.drawable = ContextCompat.getDrawable(activity, animDrawableId);
|
||||||
this.delayMessageId = delayMessageId;
|
this.delayMessageId = delayMessageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
imageButton.setImageDrawable(animatedDrawable);
|
activity.runOnUiThread(()->{
|
||||||
activity.runOnUiThread(animatedDrawable::start);
|
imageButton.setImageDrawable(drawable);
|
||||||
|
if (drawable instanceof AnimatedVectorDrawable) {
|
||||||
|
((AnimatedVectorDrawable) drawable).start();
|
||||||
|
}
|
||||||
|
ActivityUtils.vibrate(activity, 150);
|
||||||
|
ActivityUtils.toast(activity, delayMessageId, Toast.LENGTH_SHORT, Gravity.TOP);
|
||||||
|
});
|
||||||
|
|
||||||
ActivityUtils.vibrate(activity, 150);
|
|
||||||
activity.runOnUiThread(()-> ActivityUtils.toast(activity, delayMessageId, Toast.LENGTH_SHORT, Gravity.TOP));
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(delayMillis);
|
Thread.sleep(delayMillis);
|
||||||
} catch (InterruptedException ignored) {
|
} catch (InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
if (!canceled) {
|
if (!canceled) {
|
||||||
activity.runOnUiThread(()-> clickListener.onClick(null));
|
activity.runOnUiThread(()-> {
|
||||||
ActivityUtils.vibrate(activity, 1000);
|
clickListener.onClick(null);
|
||||||
|
ActivityUtils.vibrate(activity, 1000);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import android.os.Bundle;
|
|||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.util.SystemUtils;
|
import de.dennisguse.opentracks.util.SystemUtils;
|
||||||
|
|
||||||
@@ -33,7 +36,7 @@ public class TrackDeleteActivity extends AbstractActivity {
|
|||||||
|
|
||||||
public static final String EXTRA_TRACK_IDS = "track_ids";
|
public static final String EXTRA_TRACK_IDS = "track_ids";
|
||||||
|
|
||||||
private long[] trackIds;
|
private List<Track.Id> trackIds;
|
||||||
|
|
||||||
private Thread deleteThread;
|
private Thread deleteThread;
|
||||||
|
|
||||||
@@ -44,13 +47,13 @@ public class TrackDeleteActivity extends AbstractActivity {
|
|||||||
setResult(RESULT_CANCELED);
|
setResult(RESULT_CANCELED);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
trackIds = intent.getLongArrayExtra(EXTRA_TRACK_IDS);
|
trackIds = intent.getParcelableArrayListExtra(EXTRA_TRACK_IDS);
|
||||||
deleteThread = new Thread(() -> {
|
deleteThread = new Thread(() -> {
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(TrackDeleteActivity.this);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(TrackDeleteActivity.this);
|
||||||
|
|
||||||
PowerManager.WakeLock wakeLock = SystemUtils.acquireWakeLock(TrackDeleteActivity.this, null);
|
PowerManager.WakeLock wakeLock = SystemUtils.acquireWakeLock(TrackDeleteActivity.this, null);
|
||||||
|
|
||||||
for (long id : trackIds) {
|
for (Track.Id id : trackIds) {
|
||||||
if (Thread.interrupted()) {
|
if (Thread.interrupted()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
|||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
|
|
||||||
trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
||||||
long trackId = getIntent().getLongExtra(EXTRA_TRACK_ID, -1L);
|
Track.Id trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID);
|
||||||
if (trackId == -1L) {
|
if (!trackId.isValid()) {
|
||||||
Log.e(TAG, "invalid trackId");
|
Log.e(TAG, "invalid trackId");
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ import androidx.core.app.ActivityCompat;
|
|||||||
import androidx.cursoradapter.widget.ResourceCursorAdapter;
|
import androidx.cursoradapter.widget.ResourceCursorAdapter;
|
||||||
import androidx.loader.app.LoaderManager;
|
import androidx.loader.app.LoaderManager;
|
||||||
import androidx.loader.app.LoaderManager.LoaderCallbacks;
|
import androidx.loader.app.LoaderManager.LoaderCallbacks;
|
||||||
import androidx.loader.content.CursorLoader;
|
|
||||||
import androidx.loader.content.Loader;
|
import androidx.loader.content.Loader;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
||||||
@@ -60,7 +60,6 @@ import de.dennisguse.opentracks.util.ListItemUtils;
|
|||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||||
import de.dennisguse.opentracks.util.TrackUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity displaying a list of tracks.
|
* An activity displaying a list of tracks.
|
||||||
@@ -71,10 +70,6 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
|
|
||||||
private static final String TAG = TrackListActivity.class.getSimpleName();
|
private static final String TAG = TrackListActivity.class.getSimpleName();
|
||||||
|
|
||||||
private static final String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME,
|
|
||||||
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME,
|
|
||||||
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON};
|
|
||||||
|
|
||||||
// The following are set in onCreate
|
// The following are set in onCreate
|
||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
private SharedPreferences sharedPreferences;
|
private SharedPreferences sharedPreferences;
|
||||||
@@ -87,8 +82,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
private final LoaderCallbacks<Cursor> loaderCallbacks = new LoaderCallbacks<Cursor>() {
|
private final LoaderCallbacks<Cursor> loaderCallbacks = new LoaderCallbacks<Cursor>() {
|
||||||
@Override
|
@Override
|
||||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||||
return new CursorLoader(TrackListActivity.this, TracksColumns.CONTENT_URI, PROJECTION, null,
|
return ContentProviderUtils.getTracksCursorLoader(TrackListActivity.this);
|
||||||
null, TrackUtils.TRACK_SORT_ORDER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -104,7 +98,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
private boolean metricUnits = true;
|
private boolean metricUnits = true;
|
||||||
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
private Track.Id recordingTrackId = null;
|
||||||
|
|
||||||
// Callback when an item is selected in the contextual action mode
|
// Callback when an item is selected in the contextual action mode
|
||||||
private final ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
|
private final ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
|
||||||
@@ -125,8 +119,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
|
|
||||||
private boolean recordingTrackPaused;
|
private boolean recordingTrackPaused;
|
||||||
|
|
||||||
private final OnSharedPreferenceChangeListener
|
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||||
if (PreferencesUtils.isKey(TrackListActivity.this, R.string.stats_units_key, key)) {
|
if (PreferencesUtils.isKey(TrackListActivity.this, R.string.stats_units_key, key)) {
|
||||||
@@ -245,14 +238,14 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
listView.setEmptyView(findViewById(R.id.track_list_empty_view));
|
listView.setEmptyView(findViewById(R.id.track_list_empty_view));
|
||||||
listView.setOnItemClickListener((parent, view, position, trackId) -> {
|
listView.setOnItemClickListener((parent, view, position, trackId) -> {
|
||||||
Intent newIntent;
|
Intent newIntent;
|
||||||
if (trackId == recordingTrackId) {
|
if (trackId == recordingTrackId.getId()) {
|
||||||
// Is recording -> open record activity.
|
// Is recording -> open record activity.
|
||||||
newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class)
|
newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class)
|
||||||
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, trackId);
|
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, new Track.Id(trackId));
|
||||||
} else {
|
} else {
|
||||||
// Not recording -> open detail activity.
|
// Not recording -> open detail activity.
|
||||||
newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordedActivity.class)
|
newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordedActivity.class)
|
||||||
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, trackId);
|
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, new Track.Id(trackId));
|
||||||
}
|
}
|
||||||
startActivity(newIntent);
|
startActivity(newIntent);
|
||||||
});
|
});
|
||||||
@@ -269,14 +262,14 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
int categoryIndex = cursor.getColumnIndex(TracksColumns.CATEGORY);
|
int categoryIndex = cursor.getColumnIndex(TracksColumns.CATEGORY);
|
||||||
int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION);
|
int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION);
|
||||||
|
|
||||||
long trackId = cursor.getLong(idIndex);
|
Track.Id trackId = new Track.Id(cursor.getLong(idIndex));
|
||||||
boolean isRecording = trackId == recordingTrackId;
|
boolean isRecording = trackId.equals(recordingTrackId);
|
||||||
String icon = cursor.getString(iconIndex);
|
String icon = cursor.getString(iconIndex);
|
||||||
int iconId = TrackIconUtils.getIconDrawable(icon);
|
int iconId = TrackIconUtils.getIconDrawable(icon);
|
||||||
String name = cursor.getString(nameIndex);
|
String name = cursor.getString(nameIndex);
|
||||||
String totalTime = StringUtils.formatElapsedTime(cursor.getLong(totalTimeIndex));
|
String totalTime = StringUtils.formatElapsedTime(cursor.getLong(totalTimeIndex));
|
||||||
String totalDistance = StringUtils.formatDistance(TrackListActivity.this, cursor.getDouble(totalDistanceIndex), metricUnits);
|
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);
|
long startTime = cursor.getLong(startTimeIndex);
|
||||||
String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex);
|
String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex);
|
||||||
String description = cursor.getString(descriptionIndex);
|
String description = cursor.getString(descriptionIndex);
|
||||||
@@ -459,8 +452,8 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
/**
|
/**
|
||||||
* Updates the menu items with the icon specified.
|
* Updates the menu items with the icon specified.
|
||||||
*
|
*
|
||||||
* @param isGpsStarted true if gps is started
|
* @param isGpsStarted true if gps is started
|
||||||
* @param isRecording true if recording
|
* @param isRecording true if recording
|
||||||
*/
|
*/
|
||||||
private void updateGpsMenuItem(boolean isGpsStarted, boolean isRecording) {
|
private void updateGpsMenuItem(boolean isGpsStarted, boolean isRecording) {
|
||||||
if (startGpsMenuItem != null) {
|
if (startGpsMenuItem != null) {
|
||||||
@@ -478,15 +471,20 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
/**
|
/**
|
||||||
* Handles a context item selection.
|
* Handles a context item selection.
|
||||||
*
|
*
|
||||||
* @param itemId the menu item id
|
* @param itemId the menu item id
|
||||||
* @param trackIds the track ids
|
* @param longTrackIds the track ids
|
||||||
* @return true if handled.
|
* @return true if handled.
|
||||||
*/
|
*/
|
||||||
private boolean handleContextItem(int itemId, long[] trackIds) {
|
private boolean handleContextItem(int itemId, long... longTrackIds) {
|
||||||
|
Track.Id[] trackIds = new Track.Id[longTrackIds.length];
|
||||||
|
for (int i = 0; i < longTrackIds.length; i++) {
|
||||||
|
trackIds[i] = new Track.Id(longTrackIds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
Intent intent;
|
Intent intent;
|
||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case R.id.list_context_menu_show_on_map:
|
case R.id.list_context_menu_show_on_map:
|
||||||
IntentDashboardUtils.startDashboard(this, trackIds, false);
|
IntentDashboardUtils.startDashboard(this, false, trackIds);
|
||||||
return true;
|
return true;
|
||||||
case R.id.list_context_menu_share:
|
case R.id.list_context_menu_share:
|
||||||
intent = IntentUtils.newShareFileIntent(this, trackIds);
|
intent = IntentUtils.newShareFileIntent(this, trackIds);
|
||||||
|
|||||||
@@ -24,18 +24,20 @@ import android.view.MenuItem;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentPagerAdapter;
|
import androidx.fragment.app.FragmentPagerAdapter;
|
||||||
import androidx.viewpager.widget.ViewPager;
|
import androidx.viewpager.widget.ViewPager;
|
||||||
|
|
||||||
import com.google.android.material.tabs.TabLayout;
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.TrackDataHub;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.fragments.ChartFragment;
|
import de.dennisguse.opentracks.fragments.ChartFragment;
|
||||||
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
||||||
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
|
||||||
|
import de.dennisguse.opentracks.fragments.IntervalsRecordedFragment;
|
||||||
import de.dennisguse.opentracks.fragments.StatisticsRecordedFragment;
|
import de.dennisguse.opentracks.fragments.StatisticsRecordedFragment;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||||
import de.dennisguse.opentracks.settings.SettingsActivity;
|
import de.dennisguse.opentracks.settings.SettingsActivity;
|
||||||
@@ -65,8 +67,7 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
private TrackDataHub trackDataHub;
|
private TrackDataHub trackDataHub;
|
||||||
private ViewPager pager;
|
private ViewPager pager;
|
||||||
|
|
||||||
// From intent.
|
private Track track;
|
||||||
private long trackId;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -77,42 +78,8 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
|
|
||||||
trackDataHub = new TrackDataHub(this);
|
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 = 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);
|
TabLayout tabs = findViewById(R.id.track_detail_activity_tablayout);
|
||||||
tabs.setupWithViewPager(pager);
|
tabs.setupWithViewPager(pager);
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
@@ -133,8 +100,8 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
// Update UI
|
// Update UI
|
||||||
this.invalidateOptionsMenu();
|
this.invalidateOptionsMenu();
|
||||||
|
|
||||||
if (trackId != -1L) {
|
if (track != null) {
|
||||||
trackDataHub.loadTrack(trackId);
|
trackDataHub.loadTrack(track.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +139,6 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
menu.findItem(R.id.track_detail_markers).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
menu.findItem(R.id.track_detail_markers).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||||
menu.findItem(R.id.track_detail_resume_track).setVisible(!PreferencesUtils.isRecording(this));
|
menu.findItem(R.id.track_detail_resume_track).setVisible(!PreferencesUtils.isRecording(this));
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
|
||||||
setTitle(track != null ? track.getName() : "");
|
setTitle(track != null ? track.getName() : "");
|
||||||
return super.onPrepareOptionsMenu(menu);
|
return super.onPrepareOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
@@ -182,29 +148,29 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
Intent intent;
|
Intent intent;
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.track_detail_share:
|
case R.id.track_detail_share:
|
||||||
intent = IntentUtils.newShareFileIntent(this, new long[]{trackId});
|
intent = IntentUtils.newShareFileIntent(this, track.getId());
|
||||||
intent = Intent.createChooser(intent, null);
|
intent = Intent.createChooser(intent, null);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.track_detail_menu_show_on_map:
|
case R.id.track_detail_menu_show_on_map:
|
||||||
IntentDashboardUtils.startDashboard(this, new long[]{trackId}, false);
|
IntentDashboardUtils.startDashboard(this, false, track.getId());
|
||||||
return true;
|
return true;
|
||||||
case R.id.track_detail_markers:
|
case R.id.track_detail_markers:
|
||||||
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
|
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
|
||||||
.putExtra(MarkerListActivity.EXTRA_TRACK_ID, trackId);
|
.putExtra(MarkerListActivity.EXTRA_TRACK_ID, track.getId());
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.track_detail_edit:
|
case R.id.track_detail_edit:
|
||||||
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
|
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
|
||||||
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
|
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, track.getId());
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.track_detail_delete:
|
case R.id.track_detail_delete:
|
||||||
deleteTracks(new long[]{trackId});
|
deleteTracks(track.getId());
|
||||||
return true;
|
return true;
|
||||||
case R.id.track_detail_resume_track:
|
case R.id.track_detail_resume_track:
|
||||||
Intent newIntent = IntentUtils.newIntent(TrackRecordedActivity.this, TrackRecordingActivity.class)
|
Intent newIntent = IntentUtils.newIntent(TrackRecordedActivity.this, TrackRecordingActivity.class)
|
||||||
.putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, trackId);
|
.putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, track.getId());
|
||||||
startActivity(newIntent);
|
startActivity(newIntent);
|
||||||
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
|
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
|
||||||
finish();
|
finish();
|
||||||
@@ -238,12 +204,12 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleIntent(Intent intent) {
|
private void handleIntent(Intent intent) {
|
||||||
trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L);
|
Track.Id trackId = intent.getParcelableExtra(EXTRA_TRACK_ID);
|
||||||
|
|
||||||
long markerId = intent.getLongExtra(EXTRA_MARKER_ID, -1L);
|
Marker.Id waypointId = intent.getParcelableExtra(EXTRA_MARKER_ID);
|
||||||
if (markerId != -1L) {
|
if (waypointId != null) {
|
||||||
// Use the trackId from the marker
|
// Use the trackId from the marker
|
||||||
Waypoint waypoint = contentProviderUtils.getWaypoint(markerId);
|
Marker waypoint = contentProviderUtils.getMarker(waypointId);
|
||||||
if (waypoint == null) {
|
if (waypoint == null) {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
@@ -251,10 +217,12 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
trackId = waypoint.getTrackId();
|
trackId = waypoint.getTrackId();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackId == -1L) {
|
if (trackId == null) {
|
||||||
Log.e(TAG, "TrackDetailActivity needs EXTRA_TRACK_ID.");
|
Log.e(TAG, "TrackDetailActivity needs EXTRA_TRACK_ID.");
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
track = contentProviderUtils.getTrack(trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void chooseActivityType(String category) {
|
public void chooseActivityType(String category) {
|
||||||
@@ -263,8 +231,52 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChooseActivityTypeDone(String iconValue) {
|
public void onChooseActivityTypeDone(String iconValue) {
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
|
||||||
String category = getString(TrackIconUtils.getIconActivityType(iconValue));
|
String category = getString(TrackIconUtils.getIconActivityType(iconValue));
|
||||||
TrackUtils.updateTrack(this, track, null, category, null, contentProviderUtils);
|
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(track.getId());
|
||||||
|
case 1:
|
||||||
|
return IntervalsRecordedFragment.newInstance(track.getId());
|
||||||
|
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.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.fragments.ChartFragment;
|
import de.dennisguse.opentracks.fragments.ChartFragment;
|
||||||
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
||||||
|
import de.dennisguse.opentracks.fragments.IntervalsRecordingFragment;
|
||||||
import de.dennisguse.opentracks.fragments.StatisticsRecordingFragment;
|
import de.dennisguse.opentracks.fragments.StatisticsRecordingFragment;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
|
||||||
@@ -60,11 +61,14 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
private TrackController trackController;
|
private TrackController trackController;
|
||||||
|
|
||||||
// Initialized from Intent; if a new track recording is started, a new TrackId will be provided by TrackRecordingService
|
// Initialized from Intent; if a new track recording is started, a new TrackId will be provided by TrackRecordingService
|
||||||
private long trackId;
|
private Track.Id trackId;
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
private boolean recordingTrackPaused;
|
private boolean recordingTrackPaused;
|
||||||
|
|
||||||
|
// Intervals recording fragment needs Track.Id when the activity creates it.
|
||||||
|
private OnTrackIdListener intervalsListener;
|
||||||
|
|
||||||
private final Runnable bindChangedCallback = new Runnable() {
|
private final Runnable bindChangedCallback = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -78,9 +82,12 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
}
|
}
|
||||||
if (!service.isRecording()) {
|
if (!service.isRecording()) {
|
||||||
// Starts or resumes a track.
|
// Starts or resumes a track.
|
||||||
if (trackId == -1L) {
|
if (trackId == null) {
|
||||||
// trackId isn't initialized -> leads a new recording.
|
// trackId isn't initialized -> leads a new recording.
|
||||||
trackId = service.startNewTrack();
|
trackId = service.startNewTrack();
|
||||||
|
if (intervalsListener != null) {
|
||||||
|
intervalsListener.onTrackId(trackId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// trackId is initialized -> resumes the track.
|
// trackId is initialized -> resumes the track.
|
||||||
service.resumeTrack(trackId);
|
service.resumeTrack(trackId);
|
||||||
@@ -161,13 +168,15 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
contentProviderUtils = new ContentProviderUtils(this);
|
contentProviderUtils = new ContentProviderUtils(this);
|
||||||
|
|
||||||
trackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
trackId = null;
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
//Activity was recreated.
|
//Activity was recreated.
|
||||||
trackId = savedInstanceState.getLong(EXTRA_TRACK_ID, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
trackId = savedInstanceState.getParcelable(EXTRA_TRACK_ID);
|
||||||
} else {
|
} else {
|
||||||
trackId = getIntent().getLongExtra(EXTRA_TRACK_ID, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
// Resume a track
|
||||||
if (trackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT && contentProviderUtils.getTrack(trackId) == null) {
|
trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID);
|
||||||
|
if (trackId != null && contentProviderUtils.getTrack(trackId) == null) {
|
||||||
|
Log.w(TAG, "TrackId does not exists; cannot continue the recording.");
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,7 +188,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
trackDataHub = new TrackDataHub(this);
|
trackDataHub = new TrackDataHub(this);
|
||||||
|
|
||||||
pager = findViewById(R.id.track_detail_activity_view_pager);
|
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);
|
TabLayout tabs = findViewById(R.id.track_detail_activity_tablayout);
|
||||||
tabs.setupWithViewPager(pager);
|
tabs.setupWithViewPager(pager);
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
@@ -247,7 +256,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
// Update UI
|
// Update UI
|
||||||
this.invalidateOptionsMenu();
|
this.invalidateOptionsMenu();
|
||||||
|
|
||||||
if (trackId != -1L) {
|
if (trackId != null) {
|
||||||
trackDataHub.loadTrack(trackId);
|
trackDataHub.loadTrack(trackId);
|
||||||
trackController.onResume(true, recordingTrackPaused);
|
trackController.onResume(true, recordingTrackPaused);
|
||||||
}
|
}
|
||||||
@@ -265,7 +274,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putInt(CURRENT_TAB_TAG_KEY, pager.getCurrentItem());
|
outState.putInt(CURRENT_TAB_TAG_KEY, pager.getCurrentItem());
|
||||||
outState.putLong(EXTRA_TRACK_ID, trackId);
|
outState.putParcelable(EXTRA_TRACK_ID, trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -314,7 +323,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.track_detail_menu_show_on_map:
|
case R.id.track_detail_menu_show_on_map:
|
||||||
IntentDashboardUtils.startDashboard(this, new long[]{trackId}, true);
|
IntentDashboardUtils.startDashboard(this, true, trackId);
|
||||||
return true;
|
return true;
|
||||||
case R.id.track_detail_markers:
|
case R.id.track_detail_markers:
|
||||||
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
|
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
|
||||||
@@ -371,7 +380,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return 3;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -379,10 +388,12 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
public Fragment getItem(int position) {
|
public Fragment getItem(int position) {
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 0:
|
case 0:
|
||||||
return new StatisticsRecordingFragment();
|
return StatisticsRecordingFragment.newInstance();
|
||||||
case 1:
|
case 1:
|
||||||
return ChartFragment.newInstance(false);
|
return IntervalsRecordingFragment.newInstance(trackId);
|
||||||
case 2:
|
case 2:
|
||||||
|
return ChartFragment.newInstance(false);
|
||||||
|
case 3:
|
||||||
return ChartFragment.newInstance(true);
|
return ChartFragment.newInstance(true);
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
|
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
|
||||||
@@ -395,12 +406,22 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
case 0:
|
case 0:
|
||||||
return getString(R.string.track_detail_stats_tab);
|
return getString(R.string.track_detail_stats_tab);
|
||||||
case 1:
|
case 1:
|
||||||
return getString(R.string.settings_chart_by_time);
|
return getString(R.string.track_detail_intervals_tab);
|
||||||
case 2:
|
case 2:
|
||||||
|
return getString(R.string.settings_chart_by_time);
|
||||||
|
case 3:
|
||||||
return getString(R.string.settings_chart_by_distance);
|
return getString(R.string.settings_chart_by_distance);
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
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 boolean metricUnits;
|
||||||
|
private float sumDistance_m = 0f;
|
||||||
|
|
||||||
|
public IntervalStatisticsAdapter(Context context, List<IntervalStatistics.Interval> intervalList) {
|
||||||
|
super(context, R.layout.interval_stats_list_item, intervalList);
|
||||||
|
metricUnits = PreferencesUtils.isMetricUnits(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public View getView(int position, @Nullable View intervalView, @NonNull ViewGroup parent) {
|
||||||
|
IntervalStatistics.Interval interval = getItem(position);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
sumDistance_m += 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ViewHolder {
|
||||||
|
private TextView distance;
|
||||||
|
private TextView speed;
|
||||||
|
private TextView pace;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.MarkerDetailActivity;
|
import de.dennisguse.opentracks.MarkerDetailActivity;
|
||||||
import de.dennisguse.opentracks.R;
|
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.stats.ExtremityMonitor;
|
||||||
import de.dennisguse.opentracks.util.IntentUtils;
|
import de.dennisguse.opentracks.util.IntentUtils;
|
||||||
import de.dennisguse.opentracks.util.MarkerUtils;
|
import de.dennisguse.opentracks.util.MarkerUtils;
|
||||||
@@ -87,7 +87,7 @@ public class ChartView extends View {
|
|||||||
private final ChartValueSeries paceSeries;
|
private final ChartValueSeries paceSeries;
|
||||||
|
|
||||||
private final List<ChartPoint> chartPoints = new ArrayList<>();
|
private final List<ChartPoint> chartPoints = new ArrayList<>();
|
||||||
private final List<Waypoint> waypoints = new ArrayList<>();
|
private final List<Marker> waypoints = new ArrayList<>();
|
||||||
private final ExtremityMonitor xExtremityMonitor = new ExtremityMonitor();
|
private final ExtremityMonitor xExtremityMonitor = new ExtremityMonitor();
|
||||||
private final Paint axisPaint;
|
private final Paint axisPaint;
|
||||||
private final Paint xAxisMarkerPaint;
|
private final Paint xAxisMarkerPaint;
|
||||||
@@ -150,9 +150,9 @@ public class ChartView extends View {
|
|||||||
// Check if the y event is within markerHeight of the marker center
|
// Check if the y event is within markerHeight of the marker center
|
||||||
if (Math.abs(event.getY() - topBorder - spacer - markerHeight / 2f) < markerHeight) {
|
if (Math.abs(event.getY() - topBorder - spacer - markerHeight / 2f) < markerHeight) {
|
||||||
int minDistance = Integer.MAX_VALUE;
|
int minDistance = Integer.MAX_VALUE;
|
||||||
Waypoint nearestWaypoint = null;
|
Marker nearestWaypoint = null;
|
||||||
synchronized (waypoints) {
|
synchronized (waypoints) {
|
||||||
for (Waypoint waypoint : waypoints) {
|
for (Marker waypoint : waypoints) {
|
||||||
int distance = Math.abs(getX(getWaypointXValue(waypoint)) - (int) event.getX() - getScrollX());
|
int distance = Math.abs(getX(getWaypointXValue(waypoint)) - (int) event.getX() - getScrollX());
|
||||||
if (distance < minDistance) {
|
if (distance < minDistance) {
|
||||||
minDistance = distance;
|
minDistance = distance;
|
||||||
@@ -434,7 +434,7 @@ public class ChartView extends View {
|
|||||||
scrollTo(0, 0);
|
scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addWaypoint(Waypoint waypoint) {
|
public void addWaypoint(Marker waypoint) {
|
||||||
synchronized (waypoints) {
|
synchronized (waypoints) {
|
||||||
waypoints.add(waypoint);
|
waypoints.add(waypoint);
|
||||||
}
|
}
|
||||||
@@ -594,7 +594,7 @@ public class ChartView extends View {
|
|||||||
*/
|
*/
|
||||||
private void drawWaypoints(Canvas canvas) {
|
private void drawWaypoints(Canvas canvas) {
|
||||||
synchronized (waypoints) {
|
synchronized (waypoints) {
|
||||||
for (Waypoint waypoint : waypoints) {
|
for (Marker waypoint : waypoints) {
|
||||||
double xValue = getWaypointXValue(waypoint);
|
double xValue = getWaypointXValue(waypoint);
|
||||||
if (xValue > maxX) {
|
if (xValue > maxX) {
|
||||||
continue;
|
continue;
|
||||||
@@ -980,7 +980,7 @@ public class ChartView extends View {
|
|||||||
*
|
*
|
||||||
* @param waypoint the waypoint
|
* @param waypoint the waypoint
|
||||||
*/
|
*/
|
||||||
private double getWaypointXValue(Waypoint waypoint) {
|
private double getWaypointXValue(Marker waypoint) {
|
||||||
if (chartByDistance) {
|
if (chartByDistance) {
|
||||||
double lenghtInKm = waypoint.getLength() * UnitConversions.M_TO_KM;
|
double lenghtInKm = waypoint.getLength() * UnitConversions.M_TO_KM;
|
||||||
return metricUnits ? lenghtInKm : lenghtInKm * UnitConversions.KM_TO_MI;
|
return metricUnits ? lenghtInKm : lenghtInKm * UnitConversions.KM_TO_MI;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import de.dennisguse.opentracks.util.StringUtils;
|
|||||||
import de.dennisguse.opentracks.util.UnitConversions;
|
import de.dennisguse.opentracks.util.UnitConversions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates descriptions for tracks and waypoints.
|
* Generates descriptions for tracks and markers.
|
||||||
*
|
*
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -28,17 +28,17 @@ import java.util.Locale;
|
|||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.LocationUtils;
|
import de.dennisguse.opentracks.util.LocationUtils;
|
||||||
import de.dennisguse.opentracks.util.UnitConversions;
|
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
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
@@ -53,12 +53,12 @@ public class SearchEngine {
|
|||||||
TracksColumns.CATEGORY + " LIKE ?";
|
TracksColumns.CATEGORY + " LIKE ?";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WHERE query to get waypoints by name.
|
* WHERE query to get markers by name.
|
||||||
*/
|
*/
|
||||||
private static final String WAYPOINT_SELECTION_QUERY =
|
private static final String MARKER_SELECTION_QUERY =
|
||||||
WaypointsColumns.NAME + " LIKE ? OR " +
|
MarkerColumns.NAME + " LIKE ? OR " +
|
||||||
WaypointsColumns.DESCRIPTION + " LIKE ? OR " +
|
MarkerColumns.DESCRIPTION + " LIKE ? OR " +
|
||||||
WaypointsColumns.CATEGORY + " LIKE ?";
|
MarkerColumns.CATEGORY + " LIKE ?";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order of track results.
|
* Order of track results.
|
||||||
@@ -66,9 +66,9 @@ public class SearchEngine {
|
|||||||
private static final String TRACK_SELECTION_ORDER = TracksColumns._ID + " DESC LIMIT 1000";
|
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.
|
* 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;
|
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.
|
* 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;
|
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)
|
* 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;
|
return scoreDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make tracks come before waypoints.
|
// Make tracks come before markers.
|
||||||
if (r1.waypoint != null && r2.track != null) {
|
if (r1.marker != null && r2.track != null) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (r1.track != null && r2.waypoint != null) {
|
} else if (r1.track != null && r2.marker != null) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, use arbitrary ordering, by ID.
|
// Finally, use arbitrary ordering, by ID.
|
||||||
long id1 = r1.track != null ? r1.track.getId() : r1.waypoint.getId();
|
long id1 = r1.track != null ? r1.track.getId().getId() : r1.marker.getId().getId();
|
||||||
long id2 = r2.track != null ? r2.track.getId() : r2.waypoint.getId();
|
long id2 = r2.track != null ? r2.track.getId().getId() : r2.marker.getId().getId();
|
||||||
long idDiff = id2 - id1;
|
long idDiff = id2 - id1;
|
||||||
return Long.signum(idDiff);
|
return Long.signum(idDiff);
|
||||||
};
|
};
|
||||||
@@ -153,7 +153,7 @@ public class SearchEngine {
|
|||||||
TreeSet<ScoredResult> scoredResults = new TreeSet<>(SCORED_RESULT_COMPARATOR);
|
TreeSet<ScoredResult> scoredResults = new TreeSet<>(SCORED_RESULT_COMPARATOR);
|
||||||
|
|
||||||
scoreTrackResults(retrieveTracks(query), query, scoredResults);
|
scoreTrackResults(retrieveTracks(query), query, scoredResults);
|
||||||
scoreWaypointResults(retrieveWaypoints(query), query, scoredResults);
|
scoreMarkersResults(retrieveMarkers(query), query, scoredResults);
|
||||||
|
|
||||||
return 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
|
* @param query the query to retrieve for
|
||||||
*/
|
*/
|
||||||
private List<Waypoint> retrieveWaypoints(SearchQuery query) {
|
private List<Marker> retrieveMarkers(SearchQuery query) {
|
||||||
ArrayList<Waypoint> waypoints = new ArrayList<>();
|
ArrayList<Marker> markers = new ArrayList<>();
|
||||||
|
|
||||||
String queryLikeSelection2 = "%" + query.textQuery + "%";
|
String queryLikeSelection2 = "%" + query.textQuery + "%";
|
||||||
String[] waypointSelectionArgs = new String[]{
|
String[] markersSelectionArgs = new String[]{
|
||||||
queryLikeSelection2,
|
queryLikeSelection2,
|
||||||
queryLikeSelection2,
|
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) {
|
if (cursor != null) {
|
||||||
waypoints.ensureCapacity(cursor.getCount());
|
markers.ensureCapacity(cursor.getCount());
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
Waypoint waypoint = providerUtils.createWaypoint(cursor);
|
Marker marker = providerUtils.createMarker(cursor);
|
||||||
if (LocationUtils.isValidLocation(waypoint.getLocation())) {
|
if (LocationUtils.isValidLocation(marker.getLocation())) {
|
||||||
waypoints.add(waypoint);
|
markers.add(marker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return waypoints;
|
return markers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -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 markers the results to score
|
||||||
* @param query the query to score for
|
* @param query the query to score for
|
||||||
* @param output the collection to fill with scored results
|
* @param output the collection to fill with scored results
|
||||||
*/
|
*/
|
||||||
private void scoreWaypointResults(Collection<Waypoint> waypoints, SearchQuery query, Collection<ScoredResult> output) {
|
private void scoreMarkersResults(Collection<Marker> markers, SearchQuery query, Collection<ScoredResult> output) {
|
||||||
for (Waypoint waypoint : waypoints) {
|
for (Marker marker : markers) {
|
||||||
// Calculate the score.
|
// Calculate the score.
|
||||||
double score = scoreWaypointResult(query, waypoint);
|
double score = scoreMarkerResult(query, marker);
|
||||||
|
|
||||||
// Add to the output.
|
// 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 query the query to score for
|
||||||
* @param waypoint the results to score
|
* @param marker the results to score
|
||||||
* @return the score for the waypoint
|
* @return the score for the marker
|
||||||
*/
|
*/
|
||||||
private double scoreWaypointResult(SearchQuery query, Waypoint waypoint) {
|
private double scoreMarkerResult(SearchQuery query, Marker marker) {
|
||||||
double score = 1.0;
|
double score = 1.0;
|
||||||
|
|
||||||
Location location = waypoint.getLocation();
|
Location location = marker.getLocation();
|
||||||
score *= getTitleBoost(query, waypoint.getName(), waypoint.getDescription(), waypoint.getCategory());
|
score *= getTitleBoost(query, marker.getName(), marker.getDescription(), marker.getCategory());
|
||||||
score *= getDistanceBoost(query, location.getLatitude(), location.getLongitude());
|
score *= getDistanceBoost(query, location.getLatitude(), location.getLongitude());
|
||||||
score *= getTimeBoost(query, location.getTime());
|
score *= getTimeBoost(query, location.getTime());
|
||||||
|
|
||||||
// Score waypoints in the currently-selected track higher (searching inside the current track).
|
// Score markers in the currently-selected track higher (searching inside the current track).
|
||||||
if (query.currentTrackId != -1 && waypoint.getTrackId() == query.currentTrackId) {
|
if (marker.getTrackId() != null && marker.getTrackId().equals(query.currentTrackId)) {
|
||||||
score *= CURRENT_TRACK_WAYPOINT_PROMOTION;
|
score *= CURRENT_TRACK_MARKER_PROMOTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
return score;
|
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.
|
* Calculates the boosting of the score due to the field(s) in which the match occured.
|
||||||
*
|
*
|
||||||
* @param query the query to boost for
|
* @param query the query to boost for
|
||||||
* @param name the name of the track or waypoint
|
* @param name the name of the track or marker
|
||||||
* @param description the description of the track or waypoint
|
* @param description the description of the track or marker
|
||||||
* @param category the category of the track or waypoint
|
* @param category the category of the track or marker
|
||||||
* @return the total boost to be applied to the result
|
* @return the total boost to be applied to the result
|
||||||
*/
|
*/
|
||||||
private double getTitleBoost(SearchQuery query, String name, String description, String category) {
|
private double getTitleBoost(SearchQuery query, String name, String description, String category) {
|
||||||
@@ -382,10 +382,10 @@ public class SearchEngine {
|
|||||||
public static class SearchQuery {
|
public static class SearchQuery {
|
||||||
final String textQuery;
|
final String textQuery;
|
||||||
final Location currentLocation;
|
final Location currentLocation;
|
||||||
final long currentTrackId;
|
final Track.Id currentTrackId;
|
||||||
final long currentTimestamp;
|
final long currentTimestamp;
|
||||||
|
|
||||||
public SearchQuery(String textQuery, Location currentLocation, long currentTrackId, long currentTimestamp) {
|
public SearchQuery(String textQuery, Location currentLocation, Track.Id currentTrackId, long currentTimestamp) {
|
||||||
this.textQuery = textQuery.toLowerCase(Locale.getDefault());
|
this.textQuery = textQuery.toLowerCase(Locale.getDefault());
|
||||||
this.currentLocation = currentLocation;
|
this.currentLocation = currentLocation;
|
||||||
this.currentTrackId = currentTrackId;
|
this.currentTrackId = currentTrackId;
|
||||||
@@ -398,18 +398,18 @@ public class SearchEngine {
|
|||||||
*/
|
*/
|
||||||
public static class ScoredResult {
|
public static class ScoredResult {
|
||||||
public final Track track;
|
public final Track track;
|
||||||
public final Waypoint waypoint;
|
public final Marker marker;
|
||||||
final double score;
|
final double score;
|
||||||
|
|
||||||
ScoredResult(Track track, double score) {
|
ScoredResult(Track track, double score) {
|
||||||
this.track = track;
|
this.track = track;
|
||||||
this.waypoint = null;
|
this.marker = null;
|
||||||
this.score = score;
|
this.score = score;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScoredResult(Waypoint waypoint, double score) {
|
ScoredResult(Marker marker, double score) {
|
||||||
this.track = null;
|
this.track = null;
|
||||||
this.waypoint = waypoint;
|
this.marker = marker;
|
||||||
this.score = score;
|
this.score = score;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,8 +417,8 @@ public class SearchEngine {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ScoredResult ["
|
return "ScoredResult ["
|
||||||
+ (track != null ? ("trackId=" + track.getId() + ", ") : "")
|
+ (track != null ? ("trackId=" + track.getId().getId() + ", ") : "")
|
||||||
+ (waypoint != null ? ("wptId=" + waypoint.getId() + ", ") : "")
|
+ (marker != null ? ("wptId=" + marker.getId().getId() + ", ") : "")
|
||||||
+ "score=" + score + "]";
|
+ "score=" + score + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,18 +25,19 @@ import android.os.Handler;
|
|||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||||
import de.dennisguse.opentracks.util.LocationUtils;
|
import de.dennisguse.opentracks.util.LocationUtils;
|
||||||
@@ -57,14 +58,14 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
* We may display more than this number of points.
|
* We may display more than this number of points.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@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
|
@VisibleForTesting
|
||||||
@Deprecated
|
@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();
|
private static final String TAG = TrackDataHub.class.getSimpleName();
|
||||||
|
|
||||||
@@ -78,8 +79,8 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
|
||||||
// Preference values
|
// Preference values
|
||||||
private long selectedTrackId;
|
private Track.Id selectedTrackId;
|
||||||
private long recordingTrackId;
|
private Track.Id recordingTrackId;
|
||||||
private boolean recordingTrackPaused;
|
private boolean recordingTrackPaused;
|
||||||
|
|
||||||
// Track points sampling state
|
// Track points sampling state
|
||||||
@@ -89,11 +90,11 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
|
|
||||||
// Registered listeners
|
// Registered listeners
|
||||||
private ContentObserver tracksTableObserver;
|
private ContentObserver tracksTableObserver;
|
||||||
private ContentObserver waypointsTableObserver;
|
private ContentObserver markersTableObserver;
|
||||||
private ContentObserver trackPointsTableObserver;
|
private ContentObserver trackPointsTableObserver;
|
||||||
|
|
||||||
public TrackDataHub(Context context) {
|
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
|
@VisibleForTesting
|
||||||
@@ -125,13 +126,13 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
};
|
};
|
||||||
contentResolver.registerContentObserver(TracksColumns.CONTENT_URI, false, tracksTableObserver);
|
contentResolver.registerContentObserver(TracksColumns.CONTENT_URI, false, tracksTableObserver);
|
||||||
|
|
||||||
waypointsTableObserver = new ContentObserver(handler) {
|
markersTableObserver = new ContentObserver(handler) {
|
||||||
@Override
|
@Override
|
||||||
public void onChange(boolean selfChange) {
|
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) {
|
trackPointsTableObserver = new ContentObserver(handler) {
|
||||||
@Override
|
@Override
|
||||||
@@ -164,7 +165,7 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
//Unregister listeners
|
//Unregister listeners
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
contentResolver.unregisterContentObserver(tracksTableObserver);
|
contentResolver.unregisterContentObserver(tracksTableObserver);
|
||||||
contentResolver.unregisterContentObserver(waypointsTableObserver);
|
contentResolver.unregisterContentObserver(markersTableObserver);
|
||||||
contentResolver.unregisterContentObserver(trackPointsTableObserver);
|
contentResolver.unregisterContentObserver(trackPointsTableObserver);
|
||||||
|
|
||||||
if (handlerThread != null) {
|
if (handlerThread != null) {
|
||||||
@@ -174,10 +175,10 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
handler = null;
|
handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadTrack(final long trackId) {
|
public void loadTrack(final @NonNull Track.Id trackId) {
|
||||||
runInHandlerThread(() -> {
|
runInHandlerThread(() -> {
|
||||||
if (trackId == selectedTrackId) {
|
if (trackId.equals(selectedTrackId)) {
|
||||||
Log.i(TAG, "Not reloading track " + trackId);
|
Log.i(TAG, "Not reloading track " + trackId.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedTrackId = trackId;
|
selectedTrackId = trackId;
|
||||||
@@ -190,9 +191,9 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
*
|
*
|
||||||
* @param trackDataListener the track data listener
|
* @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(() -> {
|
runInHandlerThread(() -> {
|
||||||
trackDataManager.registerTrackDataListener(trackDataListener, tracksTable, waypointsTable, trackPointsTable_SampleIn, trackPointsTable_SampleOut);
|
trackDataManager.registerTrackDataListener(trackDataListener, tracksTable, markersTable, trackPointsTable_SampleIn, trackPointsTable_SampleOut);
|
||||||
if (started) {
|
if (started) {
|
||||||
loadDataForListener(trackDataListener);
|
loadDataForListener(trackDataListener);
|
||||||
}
|
}
|
||||||
@@ -212,14 +213,14 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
* Returns true if the selected track is recording.
|
* Returns true if the selected track is recording.
|
||||||
*/
|
*/
|
||||||
public boolean isSelectedTrackRecording() {
|
public boolean isSelectedTrackRecording() {
|
||||||
return selectedTrackId == recordingTrackId && PreferencesUtils.isRecording(recordingTrackId);
|
return selectedTrackId != null && selectedTrackId.equals(recordingTrackId) && PreferencesUtils.isRecording(recordingTrackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the selected track is paused.
|
* Returns true if the selected track is paused.
|
||||||
*/
|
*/
|
||||||
public boolean isSelectedTrackPaused() {
|
public boolean isSelectedTrackPaused() {
|
||||||
return selectedTrackId == recordingTrackId && recordingTrackPaused;
|
return selectedTrackId != null && selectedTrackId.equals(recordingTrackId) && recordingTrackPaused;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -249,7 +250,7 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
listener.clearTrackPoints();
|
listener.clearTrackPoints();
|
||||||
}
|
}
|
||||||
notifyTrackPointsTableUpdate(true, trackDataManager.getListenerTrackPoints_SampledIn(), trackDataManager.getListenerTrackPoints_SampledOut());
|
notifyTrackPointsTableUpdate(true, trackDataManager.getListenerTrackPoints_SampledIn(), trackDataManager.getListenerTrackPoints_SampledOut());
|
||||||
notifyWaypointsTableUpdate(trackDataManager.getListenerWaypoints());
|
notifyMarkersTableUpdate(trackDataManager.getListenerMarkers());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -276,8 +277,8 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
notifyTrackPointsTableUpdate(isOnlyListener, trackDataListeners, sampledOutListeners);
|
notifyTrackPointsTableUpdate(isOnlyListener, trackDataListeners, sampledOutListeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackDataManager.listensForWaypoints(trackDataListener)) {
|
if (trackDataManager.listensForMarkers(trackDataListener)) {
|
||||||
notifyWaypointsTableUpdate(trackDataListeners);
|
notifyMarkersTableUpdate(trackDataListeners);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,36 +298,36 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies waypoint table update.
|
* Notifies marker table update.
|
||||||
* Currently, reloads all the waypoints up to {@link #MAX_DISPLAYED_WAYPOINTS}. To be run in the {@link #handler} thread.
|
* 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
|
* @param trackDataListeners the track data listeners to notify
|
||||||
*/
|
*/
|
||||||
private void notifyWaypointsTableUpdate(Set<TrackDataListener> trackDataListeners) {
|
private void notifyMarkersTableUpdate(Set<TrackDataListener> trackDataListeners) {
|
||||||
if (trackDataListeners.isEmpty()) {
|
if (trackDataListeners.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TrackDataListener trackDataListener : trackDataListeners) {
|
for (TrackDataListener trackDataListener : trackDataListeners) {
|
||||||
trackDataListener.clearWaypoints();
|
trackDataListener.clearMarkers();
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(selectedTrackId, -1L, MAX_DISPLAYED_WAYPOINTS)) {
|
try (Cursor cursor = contentProviderUtils.getMarkerCursor(selectedTrackId, null, MAX_DISPLAYED_MARKERS)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
do {
|
do {
|
||||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursor);
|
Marker marker = contentProviderUtils.createMarker(cursor);
|
||||||
if (!LocationUtils.isValidLocation(waypoint.getLocation())) {
|
if (!LocationUtils.isValidLocation(marker.getLocation())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (TrackDataListener trackDataListener : trackDataListeners) {
|
for (TrackDataListener trackDataListener : trackDataListeners) {
|
||||||
trackDataListener.onNewWaypoint(waypoint);
|
trackDataListener.onNewMarker(marker);
|
||||||
}
|
}
|
||||||
} while (cursor.moveToNext());
|
} while (cursor.moveToNext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TrackDataListener trackDataListener : trackDataListeners) {
|
for (TrackDataListener trackDataListener : trackDataListeners) {
|
||||||
trackDataListener.onNewWaypointsDone();
|
trackDataListener.onNewMarkersDone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +357,11 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
long localLastSeenTrackPointIdId = updateSamplingState ? lastSeenTrackPointId : -1L;
|
long localLastSeenTrackPointIdId = updateSamplingState ? lastSeenTrackPointId : -1L;
|
||||||
long maxPointId = updateSamplingState ? -1L : lastSeenTrackPointId;
|
long maxPointId = updateSamplingState ? -1L : lastSeenTrackPointId;
|
||||||
|
|
||||||
|
if (selectedTrackId == null) {
|
||||||
|
Log.w(TAG, "This should not happen, but it does"); //TODO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
long lastTrackPointId = contentProviderUtils.getLastTrackPointId(selectedTrackId);
|
long lastTrackPointId = contentProviderUtils.getLastTrackPointId(selectedTrackId);
|
||||||
int samplingFrequency = -1;
|
int samplingFrequency = -1;
|
||||||
boolean includeNextPoint = false;
|
boolean includeNextPoint = false;
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.content;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener for track data changes.
|
* Listener for track data changes.
|
||||||
@@ -60,20 +60,20 @@ public interface TrackDataListener {
|
|||||||
void onNewTrackPointsDone();
|
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.
|
* Called when finish sending new markers.
|
||||||
* This gets called after every batch of calls to {@link #clearWaypoints()} and {@link #onNewWaypoint(Waypoint)}.
|
* 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 static final String TAG = TrackDataManager.class.getSimpleName();
|
||||||
|
|
||||||
private final Set<TrackDataListener> dataListenerTracks = new HashSet<>();
|
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_SampledIn = new HashSet<>();
|
||||||
private final Set<TrackDataListener> dataListenerTrackPoints_SampledOut = 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 (tracksTable) dataListenerTracks.add(trackDataListener);
|
||||||
if (waypointsTable) dataListenerWaypoints.add(trackDataListener);
|
if (markersTable) dataListenerMarkers.add(trackDataListener);
|
||||||
if (trackPointsTable_SampleIn) dataListenerTrackPoints_SampledIn.add(trackDataListener);
|
if (trackPointsTable_SampleIn) dataListenerTrackPoints_SampledIn.add(trackDataListener);
|
||||||
if (trackPointsTable_SampleOut) dataListenerTrackPoints_SampledOut.add(trackDataListener);
|
if (trackPointsTable_SampleOut) dataListenerTrackPoints_SampledOut.add(trackDataListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregisterTrackDataListener(TrackDataListener trackDataListener) {
|
void unregisterTrackDataListener(TrackDataListener trackDataListener) {
|
||||||
dataListenerTracks.add(trackDataListener);
|
dataListenerTracks.add(trackDataListener);
|
||||||
dataListenerWaypoints.add(trackDataListener);
|
dataListenerMarkers.add(trackDataListener);
|
||||||
dataListenerTrackPoints_SampledIn.add(trackDataListener);
|
dataListenerTrackPoints_SampledIn.add(trackDataListener);
|
||||||
dataListenerTrackPoints_SampledOut.add(trackDataListener);
|
dataListenerTrackPoints_SampledOut.add(trackDataListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasListeners() {
|
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() {
|
int getNumberOfListeners() {
|
||||||
Set<TrackDataListener> listener = new HashSet<>();
|
Set<TrackDataListener> listener = new HashSet<>();
|
||||||
listener.addAll(dataListenerTracks);
|
listener.addAll(dataListenerTracks);
|
||||||
listener.addAll(dataListenerWaypoints);
|
listener.addAll(dataListenerMarkers);
|
||||||
listener.addAll(dataListenerTrackPoints_SampledIn);
|
listener.addAll(dataListenerTrackPoints_SampledIn);
|
||||||
listener.addAll(dataListenerTrackPoints_SampledOut);
|
listener.addAll(dataListenerTrackPoints_SampledOut);
|
||||||
|
|
||||||
@@ -65,8 +65,8 @@ class TrackDataManager {
|
|||||||
return dataListenerTracks.contains(listener);
|
return dataListenerTracks.contains(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean listensForWaypoints(TrackDataListener listener) {
|
boolean listensForMarkers(TrackDataListener listener) {
|
||||||
return dataListenerWaypoints.contains(listener);
|
return dataListenerMarkers.contains(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean listensForTrackPoints_SampledIn(TrackDataListener listener) {
|
boolean listensForTrackPoints_SampledIn(TrackDataListener listener) {
|
||||||
@@ -81,8 +81,8 @@ class TrackDataManager {
|
|||||||
return dataListenerTracks;
|
return dataListenerTracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<TrackDataListener> getListenerWaypoints() {
|
Set<TrackDataListener> getListenerMarkers() {
|
||||||
return dataListenerWaypoints;
|
return dataListenerMarkers;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<TrackDataListener> getListenerTrackPoints_SampledIn() {
|
Set<TrackDataListener> getListenerTrackPoints_SampledIn() {
|
||||||
|
|||||||
+83
-12
@@ -18,24 +18,29 @@ package de.dennisguse.opentracks.content.data;
|
|||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A waypoint.
|
|
||||||
*
|
|
||||||
* @author Leif Hendrik Wilden
|
* @author Leif Hendrik Wilden
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public final class Waypoint {
|
public final class Marker {
|
||||||
|
|
||||||
private long id = -1L;
|
private Id id;
|
||||||
private String name = "";
|
private String name = "";
|
||||||
private String description = "";
|
private String description = "";
|
||||||
private String category = "";
|
private String category = "";
|
||||||
private String icon = "";
|
private String icon = "";
|
||||||
private long trackId = -1L;
|
private Track.Id trackId;
|
||||||
private double length = 0.0;
|
private double length = 0.0;
|
||||||
private long duration = 0;
|
private long duration = 0;
|
||||||
private Location location;
|
private Location location;
|
||||||
@@ -43,15 +48,15 @@ public final class Waypoint {
|
|||||||
private String photoUrl = "";
|
private String photoUrl = "";
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public Waypoint(@NonNull TrackPoint trackPoint) {
|
public Marker(@NonNull TrackPoint trackPoint) {
|
||||||
this.location = trackPoint.getLocation();
|
this.location = trackPoint.getLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Waypoint(@NonNull Location location) {
|
public Marker(@NonNull Location location) {
|
||||||
this.location = location;
|
this.location = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Waypoint(String name, String description, String category, String icon, long 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.name = name;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.category = category;
|
this.category = category;
|
||||||
@@ -63,11 +68,15 @@ public final class Waypoint {
|
|||||||
this.photoUrl = photoUrl;
|
this.photoUrl = photoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getId() {
|
/**
|
||||||
|
* May be null if the waypoint was not loaded from the database.
|
||||||
|
*/
|
||||||
|
public @Nullable
|
||||||
|
Id getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(long id) {
|
public void setId(Id id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,11 +112,11 @@ public final class Waypoint {
|
|||||||
this.icon = icon;
|
this.icon = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTrackId() {
|
public Track.Id getTrackId() {
|
||||||
return trackId;
|
return trackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTrackId(long trackId) {
|
public void setTrackId(Track.Id trackId) {
|
||||||
this.trackId = trackId;
|
this.trackId = trackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,4 +156,66 @@ public final class Waypoint {
|
|||||||
public boolean hasPhoto() {
|
public boolean hasPhoto() {
|
||||||
return photoUrl != null && !"".equals(photoUrl);
|
return photoUrl != null && !"".equals(photoUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Id implements Parcelable {
|
||||||
|
|
||||||
|
private final long id;
|
||||||
|
|
||||||
|
public Id(long id) {
|
||||||
|
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
|
||||||
|
public boolean isValid() {
|
||||||
|
return id != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Id id1 = (Id) o;
|
||||||
|
return id == id1.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
throw new RuntimeException("Not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel parcel, int i) {
|
||||||
|
parcel.writeLong(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<Id> CREATOR = new Parcelable.Creator<Id>() {
|
||||||
|
public Id createFromParcel(Parcel in) {
|
||||||
|
return new Id(in.readLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Id[] newArray(int size) {
|
||||||
|
return new Id[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -26,7 +26,7 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
|||||||
*
|
*
|
||||||
* @author Leif Hendrik Wilden
|
* @author Leif Hendrik Wilden
|
||||||
*/
|
*/
|
||||||
public interface WaypointsColumns extends BaseColumns {
|
public interface MarkerColumns extends BaseColumns {
|
||||||
|
|
||||||
String TABLE_NAME = "waypoints";
|
String TABLE_NAME = "waypoints";
|
||||||
Uri CONTENT_URI = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/" + TABLE_NAME);
|
Uri CONTENT_URI = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/" + TABLE_NAME);
|
||||||
@@ -16,9 +16,17 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.content.data;
|
package de.dennisguse.opentracks.content.data;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A track.
|
* A track.
|
||||||
@@ -28,7 +36,7 @@ import de.dennisguse.opentracks.stats.TrackStatistics;
|
|||||||
*/
|
*/
|
||||||
public class Track {
|
public class Track {
|
||||||
|
|
||||||
private long id = -1L;
|
private Track.Id id;
|
||||||
private UUID uuid = UUID.randomUUID();
|
private UUID uuid = UUID.randomUUID();
|
||||||
|
|
||||||
private String name = "";
|
private String name = "";
|
||||||
@@ -42,11 +50,15 @@ public class Track {
|
|||||||
public Track() {
|
public Track() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getId() {
|
/**
|
||||||
|
* May be null if the track was not loaded from the database.
|
||||||
|
*/
|
||||||
|
public @Nullable
|
||||||
|
Id getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(long id) {
|
public void setId(Id id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,4 +109,66 @@ public class Track {
|
|||||||
public void setTrackStatistics(TrackStatistics trackStatistics) {
|
public void setTrackStatistics(TrackStatistics trackStatistics) {
|
||||||
this.trackStatistics = trackStatistics;
|
this.trackStatistics = trackStatistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Id implements Parcelable {
|
||||||
|
|
||||||
|
private final long id;
|
||||||
|
|
||||||
|
public Id(long id) {
|
||||||
|
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 Track.Id of null instead
|
||||||
|
public boolean isValid() {
|
||||||
|
return id != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Id id1 = (Id) o;
|
||||||
|
return id == id1.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
throw new RuntimeException("Not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel parcel, int i) {
|
||||||
|
parcel.writeLong(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<Track.Id> CREATOR = new Parcelable.Creator<Track.Id>() {
|
||||||
|
public Track.Id createFromParcel(Parcel in) {
|
||||||
|
return new Track.Id(in.readLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Track.Id[] newArray(int size) {
|
||||||
|
return new Track.Id[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,10 +59,12 @@ public class TrackPoint {
|
|||||||
location.setTime(time);
|
location.setTime(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated //See #316
|
||||||
public static TrackPoint createPause() {
|
public static TrackPoint createPause() {
|
||||||
return createPauseWithTime(System.currentTimeMillis());
|
return createPauseWithTime(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated //See #316
|
||||||
public static TrackPoint createPauseWithTime(long time) {
|
public static TrackPoint createPauseWithTime(long time) {
|
||||||
Location pause = new Location(LocationManager.GPS_PROVIDER);
|
Location pause = new Location(LocationManager.GPS_PROVIDER);
|
||||||
pause.setLongitude(0);
|
pause.setLongitude(0);
|
||||||
@@ -71,10 +73,12 @@ public class TrackPoint {
|
|||||||
return new TrackPoint(pause);
|
return new TrackPoint(pause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated //See #316
|
||||||
public static TrackPoint createResume() {
|
public static TrackPoint createResume() {
|
||||||
return createResumeWithTime(System.currentTimeMillis());
|
return createResumeWithTime(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated //See #316
|
||||||
public static TrackPoint createResumeWithTime(long time) {
|
public static TrackPoint createResumeWithTime(long time) {
|
||||||
Location resume = new Location(LocationManager.GPS_PROVIDER);
|
Location resume = new Location(LocationManager.GPS_PROVIDER);
|
||||||
resume.setLongitude(0);
|
resume.setLongitude(0);
|
||||||
|
|||||||
+206
-192
@@ -23,9 +23,13 @@ import android.database.Cursor;
|
|||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.loader.content.CursorLoader;
|
||||||
|
import androidx.loader.content.Loader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -36,14 +40,15 @@ import java.util.UUID;
|
|||||||
import de.dennisguse.opentracks.BuildConfig;
|
import de.dennisguse.opentracks.BuildConfig;
|
||||||
import de.dennisguse.opentracks.android.ContentResolverWrapper;
|
import de.dennisguse.opentracks.android.ContentResolverWrapper;
|
||||||
import de.dennisguse.opentracks.android.IContentResolver;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
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.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
|
import de.dennisguse.opentracks.util.TrackUtils;
|
||||||
import de.dennisguse.opentracks.util.UUIDUtils;
|
import de.dennisguse.opentracks.util.UUIDUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,8 +69,8 @@ public class ContentProviderUtils {
|
|||||||
// The base URI for the app's content provider.
|
// The base URI for the app's content provider.
|
||||||
public static final String CONTENT_BASE_URI = "content://" + AUTHORITY_PACKAGE;
|
public static final String CONTENT_BASE_URI = "content://" + AUTHORITY_PACKAGE;
|
||||||
|
|
||||||
// Maximum number of waypoints that will be loaded at one time.
|
// Maximum number of markers that will be loaded at one time.
|
||||||
public static final int MAX_LOADED_WAYPOINTS_POINTS = 10000;
|
public static final int MAX_LOADED_MARKERS = 10000;
|
||||||
private static final String ID_SEPARATOR = ",";
|
private static final String ID_SEPARATOR = ",";
|
||||||
|
|
||||||
private final IContentResolver contentResolver;
|
private final IContentResolver contentResolver;
|
||||||
@@ -84,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.
|
* Only keeps the track id.
|
||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
public void clearTrack(long trackId) {
|
public void clearTrack(Track.Id trackId) {
|
||||||
deleteTrackPointsAndWaypoints(trackId);
|
deleteTrackPointsAndMarkers(trackId);
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
track.setId(trackId);
|
track.setId(trackId);
|
||||||
updateTrack(track);
|
updateTrack(track);
|
||||||
@@ -121,7 +126,7 @@ public class ContentProviderUtils {
|
|||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||||
if (!cursor.isNull(idIndex)) {
|
if (!cursor.isNull(idIndex)) {
|
||||||
track.setId(cursor.getLong(idIndex));
|
track.setId(new Track.Id(cursor.getLong(idIndex)));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(uuidIndex)) {
|
if (!cursor.isNull(uuidIndex)) {
|
||||||
track.setUuid(UUIDUtils.fromBytes(cursor.getBlob(uuidIndex)));
|
track.setUuid(UUIDUtils.fromBytes(cursor.getBlob(uuidIndex)));
|
||||||
@@ -171,7 +176,7 @@ public class ContentProviderUtils {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void deleteAllTracks(Context context) {
|
public void deleteAllTracks(Context context) {
|
||||||
contentResolver.delete(TrackPointsColumns.CONTENT_URI_BY_ID, null, null);
|
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
|
// Delete tracks last since it triggers a database vaccum call
|
||||||
contentResolver.delete(TracksColumns.CONTENT_URI, null, null);
|
contentResolver.delete(TracksColumns.CONTENT_URI, null, null);
|
||||||
|
|
||||||
@@ -184,30 +189,28 @@ public class ContentProviderUtils {
|
|||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
public void deleteTrack(Context context, long trackId) {
|
public void deleteTrack(Context context, Track.Id trackId) {
|
||||||
deleteTrackPointsAndWaypoints(trackId);
|
if (trackId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deleteTrackPointsAndMarkers(trackId);
|
||||||
|
|
||||||
// Delete track folder resources.
|
// Delete track folder resources.
|
||||||
FileUtils.deleteDirectoryRecurse(FileUtils.getPhotoDir(context, trackId));
|
FileUtils.deleteDirectoryRecurse(FileUtils.getPhotoDir(context, trackId));
|
||||||
|
|
||||||
// Delete track last since it triggers a database vacuum call
|
// Delete track last since it triggers a database vacuum call
|
||||||
contentResolver.delete(TracksColumns.CONTENT_URI, TracksColumns._ID + "=?", new String[]{Long.toString(trackId)});
|
contentResolver.delete(TracksColumns.CONTENT_URI, TracksColumns._ID + "=?", new String[]{Long.toString(trackId.getId())});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void deleteTrackPointsAndMarkers(@NonNull Track.Id trackId) {
|
||||||
* Deletes trackPoints and waypoints of a track.
|
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
*
|
|
||||||
* @param trackId the track id
|
|
||||||
*/
|
|
||||||
private void deleteTrackPointsAndWaypoints(long trackId) {
|
|
||||||
String[] selectionArgs = new String[]{Long.toString(trackId)};
|
|
||||||
|
|
||||||
contentResolver.delete(TrackPointsColumns.CONTENT_URI_BY_ID, TrackPointsColumns.TRACKID + "=?", selectionArgs);
|
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
|
@VisibleForTesting
|
||||||
public List<Track> getAllTracks() {
|
public List<Track> getTracks() {
|
||||||
ArrayList<Track> tracks = new ArrayList<>();
|
ArrayList<Track> tracks = new ArrayList<>();
|
||||||
try (Cursor cursor = getTrackCursor(null, null, TracksColumns._ID)) {
|
try (Cursor cursor = getTrackCursor(null, null, TracksColumns._ID)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
@@ -220,6 +223,17 @@ public class ContentProviderUtils {
|
|||||||
return tracks;
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Loader<Cursor> getTracksCursorLoader(Context context) {
|
||||||
|
String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME,
|
||||||
|
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME,
|
||||||
|
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON};
|
||||||
|
|
||||||
|
return new CursorLoader(context, TracksColumns.CONTENT_URI, PROJECTION, null, null, TrackUtils.TRACK_SORT_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
//TODO Do not use; rather get the proper TrackId (e.g., resume a track might give you some weird effects).
|
||||||
|
@VisibleForTesting
|
||||||
public Track getLastTrack() {
|
public Track getLastTrack() {
|
||||||
try (Cursor cursor = getTrackCursor(null, null, TracksColumns.STARTTIME + " DESC")) {
|
try (Cursor cursor = getTrackCursor(null, null, TracksColumns.STARTTIME + " DESC")) {
|
||||||
// Using the same order as shown in the track list
|
// Using the same order as shown in the track list
|
||||||
@@ -233,11 +247,11 @@ public class ContentProviderUtils {
|
|||||||
/**
|
/**
|
||||||
* @param trackId the track id.
|
* @param trackId the track id.
|
||||||
*/
|
*/
|
||||||
public Track getTrack(long trackId) {
|
public Track getTrack(Track.Id trackId) {
|
||||||
if (trackId < 0) {
|
if (trackId == null || !trackId.isValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try (Cursor cursor = getTrackCursor(TracksColumns._ID + "=?", new String[]{Long.toString(trackId)}, null)) {
|
try (Cursor cursor = getTrackCursor(TracksColumns._ID + "=?", new String[]{Long.toString(trackId.getId())}, null)) {
|
||||||
if (cursor != null && cursor.moveToNext()) {
|
if (cursor != null && cursor.moveToNext()) {
|
||||||
return createTrack(cursor);
|
return createTrack(cursor);
|
||||||
}
|
}
|
||||||
@@ -288,7 +302,7 @@ public class ContentProviderUtils {
|
|||||||
* @param track the track
|
* @param track the track
|
||||||
*/
|
*/
|
||||||
public void updateTrack(Track track) {
|
public void updateTrack(Track track) {
|
||||||
contentResolver.update(TracksColumns.CONTENT_URI, createContentValues(track), TracksColumns._ID + "=?", new String[]{Long.toString(track.getId())});
|
contentResolver.update(TracksColumns.CONTENT_URI, createContentValues(track), TracksColumns._ID + "=?", new String[]{Long.toString(track.getId().getId())});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContentValues createContentValues(Track track) {
|
private ContentValues createContentValues(Track track) {
|
||||||
@@ -296,8 +310,8 @@ public class ContentProviderUtils {
|
|||||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||||
|
|
||||||
// Value < 0 indicates no id is available
|
// Value < 0 indicates no id is available
|
||||||
if (track.getId() >= 0) {
|
if (track.getId() != null && track.getId().isValid()) {
|
||||||
values.put(TracksColumns._ID, track.getId());
|
values.put(TracksColumns._ID, track.getId().getId());
|
||||||
}
|
}
|
||||||
values.put(TracksColumns.UUID, UUIDUtils.toBytes(track.getUuid()));
|
values.put(TracksColumns.UUID, UUIDUtils.toBytes(track.getUuid()));
|
||||||
values.put(TracksColumns.NAME, track.getName());
|
values.put(TracksColumns.NAME, track.getName());
|
||||||
@@ -319,28 +333,22 @@ public class ContentProviderUtils {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Marker createMarker(Cursor cursor) {
|
||||||
/**
|
int idIndex = cursor.getColumnIndexOrThrow(MarkerColumns._ID);
|
||||||
* Creates a waypoint from a cursor.
|
int nameIndex = cursor.getColumnIndexOrThrow(MarkerColumns.NAME);
|
||||||
*
|
int descriptionIndex = cursor.getColumnIndexOrThrow(MarkerColumns.DESCRIPTION);
|
||||||
* @param cursor the cursor pointing to the waypoint
|
int categoryIndex = cursor.getColumnIndexOrThrow(MarkerColumns.CATEGORY);
|
||||||
*/
|
int iconIndex = cursor.getColumnIndexOrThrow(MarkerColumns.ICON);
|
||||||
public Waypoint createWaypoint(Cursor cursor) {
|
int trackIdIndex = cursor.getColumnIndexOrThrow(MarkerColumns.TRACKID);
|
||||||
int idIndex = cursor.getColumnIndexOrThrow(WaypointsColumns._ID);
|
int lengthIndex = cursor.getColumnIndexOrThrow(MarkerColumns.LENGTH);
|
||||||
int nameIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.NAME);
|
int durationIndex = cursor.getColumnIndexOrThrow(MarkerColumns.DURATION);
|
||||||
int descriptionIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.DESCRIPTION);
|
int longitudeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.LONGITUDE);
|
||||||
int categoryIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.CATEGORY);
|
int latitudeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.LATITUDE);
|
||||||
int iconIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ICON);
|
int timeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.TIME);
|
||||||
int trackIdIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.TRACKID);
|
int altitudeIndex = cursor.getColumnIndexOrThrow(MarkerColumns.ALTITUDE);
|
||||||
int lengthIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.LENGTH);
|
int accuracyIndex = cursor.getColumnIndexOrThrow(MarkerColumns.ACCURACY);
|
||||||
int durationIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.DURATION);
|
int bearingIndex = cursor.getColumnIndexOrThrow(MarkerColumns.BEARING);
|
||||||
int longitudeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.LONGITUDE);
|
int photoUrlIndex = cursor.getColumnIndexOrThrow(MarkerColumns.PHOTOURL);
|
||||||
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);
|
|
||||||
|
|
||||||
Location location = new Location("");
|
Location location = new Location("");
|
||||||
if (!cursor.isNull(longitudeIndex) && !cursor.isNull(latitudeIndex)) {
|
if (!cursor.isNull(longitudeIndex) && !cursor.isNull(latitudeIndex)) {
|
||||||
@@ -360,59 +368,56 @@ public class ContentProviderUtils {
|
|||||||
location.setBearing(cursor.getFloat(bearingIndex));
|
location.setBearing(cursor.getFloat(bearingIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
Waypoint waypoint = new Waypoint(location);
|
Marker marker = new Marker(location);
|
||||||
|
|
||||||
if (!cursor.isNull(idIndex)) {
|
if (!cursor.isNull(idIndex)) {
|
||||||
waypoint.setId(cursor.getLong(idIndex));
|
marker.setId(new Marker.Id(cursor.getLong(idIndex)));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(nameIndex)) {
|
if (!cursor.isNull(nameIndex)) {
|
||||||
waypoint.setName(cursor.getString(nameIndex));
|
marker.setName(cursor.getString(nameIndex));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(descriptionIndex)) {
|
if (!cursor.isNull(descriptionIndex)) {
|
||||||
waypoint.setDescription(cursor.getString(descriptionIndex));
|
marker.setDescription(cursor.getString(descriptionIndex));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(categoryIndex)) {
|
if (!cursor.isNull(categoryIndex)) {
|
||||||
waypoint.setCategory(cursor.getString(categoryIndex));
|
marker.setCategory(cursor.getString(categoryIndex));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(iconIndex)) {
|
if (!cursor.isNull(iconIndex)) {
|
||||||
waypoint.setIcon(cursor.getString(iconIndex));
|
marker.setIcon(cursor.getString(iconIndex));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(trackIdIndex)) {
|
if (!cursor.isNull(trackIdIndex)) {
|
||||||
waypoint.setTrackId(cursor.getLong(trackIdIndex));
|
marker.setTrackId(new Track.Id(cursor.getLong(trackIdIndex)));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(lengthIndex)) {
|
if (!cursor.isNull(lengthIndex)) {
|
||||||
waypoint.setLength(cursor.getFloat(lengthIndex));
|
marker.setLength(cursor.getFloat(lengthIndex));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(durationIndex)) {
|
if (!cursor.isNull(durationIndex)) {
|
||||||
waypoint.setDuration(cursor.getLong(durationIndex));
|
marker.setDuration(cursor.getLong(durationIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cursor.isNull(photoUrlIndex)) {
|
if (!cursor.isNull(photoUrlIndex)) {
|
||||||
waypoint.setPhotoUrl(cursor.getString(photoUrlIndex));
|
marker.setPhotoUrl(cursor.getString(photoUrlIndex));
|
||||||
}
|
}
|
||||||
return waypoint;
|
return marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteWaypoint(Context context, long waypointId) {
|
public void deleteMarker(Context context, Marker.Id markerId) {
|
||||||
final Waypoint waypoint = getWaypoint(waypointId);
|
final Marker marker = getMarker(markerId);
|
||||||
deleteWaypointPhoto(context, waypoint);
|
deleteMarkerPhoto(context, marker);
|
||||||
contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns._ID + "=?", new String[]{Long.toString(waypointId)});
|
contentResolver.delete(MarkerColumns.CONTENT_URI, MarkerColumns._ID + "=?", new String[]{Long.toString(markerId.getId())});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the next waypoint number.
|
* @return -1 if not able to get the next marker number.
|
||||||
*
|
|
||||||
* @param trackId the track id
|
|
||||||
* @return -1 if not able to get the next waypoint number.
|
|
||||||
*/
|
*/
|
||||||
public int getNextWaypointNumber(long trackId) {
|
public int getNextMarkerNumber(Track.Id trackId) {
|
||||||
if (trackId < 0) {
|
if (!trackId.isValid()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
String[] projection = {WaypointsColumns._ID};
|
String[] projection = {MarkerColumns._ID};
|
||||||
String selection = WaypointsColumns.TRACKID + "=?";
|
String selection = MarkerColumns.TRACKID + "=?";
|
||||||
String[] selectionArgs = new String[]{Long.toString(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) {
|
if (cursor != null) {
|
||||||
return cursor.getCount();
|
return cursor.getCount();
|
||||||
}
|
}
|
||||||
@@ -420,84 +425,94 @@ public class ContentProviderUtils {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Waypoint getWaypoint(long waypointId) {
|
public Marker getMarker(Marker.Id markerId) {
|
||||||
if (waypointId < 0) {
|
if (!markerId.isValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try (Cursor cursor = getWaypointCursor(null, WaypointsColumns._ID + "=?",
|
try (Cursor cursor = getMarkerCursor(null, MarkerColumns._ID + "=?",
|
||||||
new String[]{Long.toString(waypointId)}, WaypointsColumns._ID, 1)) {
|
new String[]{Long.toString(markerId.getId())}, MarkerColumns._ID, 1)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return createWaypoint(cursor);
|
return createMarker(cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a waypoint cursor.
|
* The caller owns the returned cursor and is responsible for closing it.
|
||||||
* he caller owns the returned cursor and is responsible for closing it.
|
|
||||||
*
|
*
|
||||||
* @param selection the selection. Can be null
|
* @param selection the selection. Can be null
|
||||||
* @param selectionArgs the selection arguments. Can be null
|
* @param selectionArgs the selection arguments. Can be null
|
||||||
* @param sortOrder the sort order. 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) {
|
public Cursor getMarkerCursor(String selection, String[] selectionArgs, String sortOrder, int maxCount) {
|
||||||
return getWaypointCursor(null, selection, selectionArgs, sortOrder, maxWaypoints);
|
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.
|
* The caller owns the returned cursor and is responsible for closing it.
|
||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
* @param minWaypointId the minimum waypoint id. -1L to ignore
|
* @param minMarkerId the minimum marker id. null to ignore
|
||||||
* @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(long trackId, long minWaypointId, int maxWaypoints) {
|
public Cursor getMarkerCursor(Track.Id trackId, @Nullable Marker.Id minMarkerId, int maxCount) {
|
||||||
if (trackId < 0) {
|
if (!trackId.isValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String selection;
|
String selection;
|
||||||
String[] selectionArgs;
|
String[] selectionArgs;
|
||||||
if (minWaypointId >= 0) {
|
if (minMarkerId != null && minMarkerId.isValid()) {
|
||||||
selection = WaypointsColumns.TRACKID + "=? AND " + WaypointsColumns._ID + ">=?";
|
selection = MarkerColumns.TRACKID + "=? AND " + MarkerColumns._ID + ">=?";
|
||||||
selectionArgs = new String[]{Long.toString(trackId), Long.toString(minWaypointId)};
|
selectionArgs = new String[]{Long.toString(trackId.getId()), Long.toString(minMarkerId.getId())};
|
||||||
} else {
|
} else {
|
||||||
selection = WaypointsColumns.TRACKID + "=?";
|
selection = MarkerColumns.TRACKID + "=?";
|
||||||
selectionArgs = new String[]{Long.toString(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
|
@VisibleForTesting
|
||||||
public List<Waypoint> getWaypoints(long trackId) {
|
public List<Marker> getMarkers(Track.Id trackId) {
|
||||||
ArrayList<Waypoint> waypoints = new ArrayList<>();
|
ArrayList<Marker> markers = new ArrayList<>();
|
||||||
try (Cursor cursor = getWaypointCursor(trackId, -1L, -1)) {
|
try (Cursor cursor = getMarkerCursor(trackId, null, -1)) {
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
do {
|
do {
|
||||||
waypoints.add(createWaypoint(cursor));
|
markers.add(createMarker(cursor));
|
||||||
} while (cursor.moveToNext());
|
} while (cursor.moveToNext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return waypoints;
|
return markers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static Loader<Cursor> getMarkersLoader(Context context, @Nullable Track.Id trackId) {
|
||||||
* Gets the number of waypoints for a track.
|
final String[] PROJECTION = new String[]{MarkerColumns._ID,
|
||||||
*
|
MarkerColumns.NAME, MarkerColumns.DESCRIPTION, MarkerColumns.CATEGORY,
|
||||||
* @param trackId the track id
|
MarkerColumns.TIME, MarkerColumns.PHOTOURL,
|
||||||
*/
|
MarkerColumns.LATITUDE, MarkerColumns.LONGITUDE};
|
||||||
public int getWaypointCount(long trackId) {
|
|
||||||
if (trackId < 0) {
|
if (trackId != null) {
|
||||||
|
return new CursorLoader(context, MarkerColumns.CONTENT_URI, PROJECTION,
|
||||||
|
MarkerColumns.TRACKID + "=?",
|
||||||
|
new String[]{String.valueOf(trackId.getId())}, null);
|
||||||
|
} else {
|
||||||
|
return new CursorLoader(context, MarkerColumns.CONTENT_URI, PROJECTION, null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated //TODO Expose information via Cursor
|
||||||
|
public int getMarkerCount(Track.Id trackId) {
|
||||||
|
if (!trackId.isValid()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] projection = new String[]{"count(*) AS count"};
|
String[] projection = new String[]{"count(*) AS count"};
|
||||||
String selection = WaypointsColumns.TRACKID + "=?";
|
String selection = MarkerColumns.TRACKID + "=?";
|
||||||
String[] selectionArgs = new String[]{Long.toString(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) {
|
if (cursor == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -507,26 +522,17 @@ public class ContentProviderUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a waypoint.
|
* @return the content provider URI of the inserted marker.
|
||||||
*
|
|
||||||
* @param waypoint the waypoint
|
|
||||||
* @return the content provider URI of the inserted waypoint.
|
|
||||||
*/
|
*/
|
||||||
public Uri insertWaypoint(Waypoint waypoint) {
|
public Uri insertMarker(@NonNull Marker marker) {
|
||||||
waypoint.setId(-1L);
|
marker.setId(null);
|
||||||
return contentResolver.insert(WaypointsColumns.CONTENT_URI, createContentValues(waypoint));
|
return contentResolver.insert(MarkerColumns.CONTENT_URI, createContentValues(marker));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void deleteMarkerPhoto(Context context, Marker marker) {
|
||||||
* Delete waypoint's photo if any.
|
if (marker != null && marker.hasPhoto()) {
|
||||||
*
|
Uri uri = marker.getPhotoURI();
|
||||||
* @param context the context object.
|
File file = FileUtils.getPhotoFileIfExists(context, marker.getTrackId(), uri);
|
||||||
* @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);
|
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
File parent = file.getParentFile();
|
File parent = file.getParentFile();
|
||||||
file.delete();
|
file.delete();
|
||||||
@@ -538,70 +544,67 @@ public class ContentProviderUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a waypoint.
|
* @param updateMarker the marker with updated data.
|
||||||
* Returns true if successful.
|
* @return true if successful.
|
||||||
*
|
|
||||||
* @param updatedWaypoint the waypoint with updated data.
|
|
||||||
*/
|
*/
|
||||||
public boolean updateWaypoint(Context context, Waypoint updatedWaypoint) {
|
public boolean updateMarker(Context context, Marker updateMarker) {
|
||||||
Waypoint savedWaypoint = getWaypoint(updatedWaypoint.getId());
|
Marker savedMarker = getMarker(updateMarker.getId());
|
||||||
if (!updatedWaypoint.hasPhoto()) {
|
if (!updateMarker.hasPhoto()) {
|
||||||
deleteWaypointPhoto(context, savedWaypoint);
|
deleteMarkerPhoto(context, savedMarker);
|
||||||
}
|
}
|
||||||
int rows = contentResolver.update(WaypointsColumns.CONTENT_URI, createContentValues(updatedWaypoint), WaypointsColumns._ID + "=?", new String[]{Long.toString(updatedWaypoint.getId())});
|
int rows = contentResolver.update(MarkerColumns.CONTENT_URI, createContentValues(updateMarker), MarkerColumns._ID + "=?", new String[]{Long.toString(updateMarker.getId().getId())});
|
||||||
return rows == 1;
|
return rows == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentValues createContentValues(Waypoint waypoint) {
|
ContentValues createContentValues(@NonNull Marker marker) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
|
||||||
// Value < 0 indicates no id is available
|
if (marker.getId() != null && marker.getId().isValid()) {
|
||||||
if (waypoint.getId() >= 0) {
|
values.put(MarkerColumns._ID, marker.getId().getId());
|
||||||
values.put(WaypointsColumns._ID, waypoint.getId());
|
|
||||||
}
|
}
|
||||||
values.put(WaypointsColumns.NAME, waypoint.getName());
|
values.put(MarkerColumns.NAME, marker.getName());
|
||||||
values.put(WaypointsColumns.DESCRIPTION, waypoint.getDescription());
|
values.put(MarkerColumns.DESCRIPTION, marker.getDescription());
|
||||||
values.put(WaypointsColumns.CATEGORY, waypoint.getCategory());
|
values.put(MarkerColumns.CATEGORY, marker.getCategory());
|
||||||
values.put(WaypointsColumns.ICON, waypoint.getIcon());
|
values.put(MarkerColumns.ICON, marker.getIcon());
|
||||||
values.put(WaypointsColumns.TRACKID, waypoint.getTrackId());
|
if (marker.getTrackId() != null) {
|
||||||
values.put(WaypointsColumns.LENGTH, waypoint.getLength());
|
values.put(MarkerColumns.TRACKID, marker.getTrackId().getId());
|
||||||
values.put(WaypointsColumns.DURATION, waypoint.getDuration());
|
}
|
||||||
|
values.put(MarkerColumns.LENGTH, marker.getLength());
|
||||||
|
values.put(MarkerColumns.DURATION, marker.getDuration());
|
||||||
|
|
||||||
Location location = waypoint.getLocation();
|
Location location = marker.getLocation();
|
||||||
values.put(WaypointsColumns.LONGITUDE, (int) (location.getLongitude() * 1E6));
|
values.put(MarkerColumns.LONGITUDE, (int) (location.getLongitude() * 1E6));
|
||||||
values.put(WaypointsColumns.LATITUDE, (int) (location.getLatitude() * 1E6));
|
values.put(MarkerColumns.LATITUDE, (int) (location.getLatitude() * 1E6));
|
||||||
values.put(WaypointsColumns.TIME, location.getTime());
|
values.put(MarkerColumns.TIME, location.getTime());
|
||||||
if (location.hasAltitude()) {
|
if (location.hasAltitude()) {
|
||||||
values.put(WaypointsColumns.ALTITUDE, location.getAltitude());
|
values.put(MarkerColumns.ALTITUDE, location.getAltitude());
|
||||||
}
|
}
|
||||||
if (location.hasAccuracy()) {
|
if (location.hasAccuracy()) {
|
||||||
values.put(WaypointsColumns.ACCURACY, location.getAccuracy());
|
values.put(MarkerColumns.ACCURACY, location.getAccuracy());
|
||||||
}
|
}
|
||||||
if (location.hasBearing()) {
|
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;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a waypoint cursor.
|
|
||||||
*
|
|
||||||
* @param projection the projection
|
* @param projection the projection
|
||||||
* @param selection the selection
|
* @param selection the selection
|
||||||
* @param selectionArgs the selection args
|
* @param selectionArgs the selection args
|
||||||
* @param sortOrder the sort order
|
* @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) {
|
if (sortOrder == null) {
|
||||||
sortOrder = WaypointsColumns._ID;
|
sortOrder = MarkerColumns._ID;
|
||||||
}
|
}
|
||||||
if (maxWaypoints >= 0) {
|
if (maxCount >= 0) {
|
||||||
sortOrder += " LIMIT " + maxWaypoints;
|
sortOrder += " LIMIT " + maxCount;
|
||||||
}
|
}
|
||||||
return contentResolver.query(WaypointsColumns.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
|
return contentResolver.query(MarkerColumns.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -656,7 +659,7 @@ public class ContentProviderUtils {
|
|||||||
* @return the number of trackPoints inserted
|
* @return the number of trackPoints inserted
|
||||||
*/
|
*/
|
||||||
//TODO Only used for testing and file import; might be better to replace it.
|
//TODO Only used for testing and file import; might be better to replace it.
|
||||||
public int bulkInsertTrackPoint(TrackPoint[] trackPoints, long trackId) {
|
public int bulkInsertTrackPoint(TrackPoint[] trackPoints, Track.Id trackId) {
|
||||||
ContentValues[] values = new ContentValues[trackPoints.length];
|
ContentValues[] values = new ContentValues[trackPoints.length];
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
values[i] = createContentValues(trackPoints[i], trackId);
|
values[i] = createContentValues(trackPoints[i], trackId);
|
||||||
@@ -666,23 +669,23 @@ public class ContentProviderUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the first location id for a track.
|
* Gets the first location id for a track.
|
||||||
* Returns -1L if it doesn't exist.
|
* Returns null if it doesn't exist.
|
||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public long getFirstTrackPointId(long trackId) {
|
public Track.Id getFirstTrackPointId(Track.Id trackId) {
|
||||||
if (trackId < 0) {
|
if (!trackId.isValid()) {
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
String selection = TrackPointsColumns._ID + "=(SELECT MIN(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=?)";
|
String selection = TrackPointsColumns._ID + "=(SELECT MIN(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=?)";
|
||||||
String[] selectionArgs = new String[]{Long.toString(trackId)};
|
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
try (Cursor cursor = getTrackPointCursor(new String[]{TrackPointsColumns._ID}, selection, selectionArgs, TrackPointsColumns._ID)) {
|
try (Cursor cursor = getTrackPointCursor(new String[]{TrackPointsColumns._ID}, selection, selectionArgs, TrackPointsColumns._ID)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return cursor.getLong(cursor.getColumnIndexOrThrow(TrackPointsColumns._ID));
|
return new Track.Id(cursor.getLong(cursor.getColumnIndexOrThrow(TrackPointsColumns._ID)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -692,12 +695,13 @@ public class ContentProviderUtils {
|
|||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public long getLastTrackPointId(long trackId) {
|
public long getLastTrackPointId(Track.Id trackId) {
|
||||||
if (trackId < 0) {
|
if (trackId == null || !trackId.isValid()) {
|
||||||
|
Log.w(TAG, "Fix callers who do this.");
|
||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") from " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=?)";
|
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") from " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=?)";
|
||||||
String[] selectionArgs = new String[]{Long.toString(trackId)};
|
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
try (Cursor cursor = getTrackPointCursor(new String[]{TrackPointsColumns._ID}, selection, selectionArgs, TrackPointsColumns._ID)) {
|
try (Cursor cursor = getTrackPointCursor(new String[]{TrackPointsColumns._ID}, selection, selectionArgs, TrackPointsColumns._ID)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return cursor.getLong(cursor.getColumnIndexOrThrow(TrackPointsColumns._ID));
|
return cursor.getLong(cursor.getColumnIndexOrThrow(TrackPointsColumns._ID));
|
||||||
@@ -713,12 +717,12 @@ public class ContentProviderUtils {
|
|||||||
* @param location the location
|
* @param location the location
|
||||||
* @return trackPoint id if the location is in the track. -1L otherwise.
|
* @return trackPoint id if the location is in the track. -1L otherwise.
|
||||||
*/
|
*/
|
||||||
public long getTrackPointId(long trackId, Location location) {
|
public long getTrackPointId(Track.Id trackId, Location location) {
|
||||||
if (trackId < 0) {
|
if (!trackId.isValid()) {
|
||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns.TIME + "=?)";
|
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns.TIME + "=?)";
|
||||||
String[] selectionArgs = new String[]{Long.toString(trackId), Long.toString(location.getTime())};
|
String[] selectionArgs = new String[]{Long.toString(trackId.getId()), Long.toString(location.getTime())};
|
||||||
try (Cursor cursor = getTrackPointCursor(new String[]{TrackPointsColumns._ID}, selection, selectionArgs, TrackPointsColumns._ID)) {
|
try (Cursor cursor = getTrackPointCursor(new String[]{TrackPointsColumns._ID}, selection, selectionArgs, TrackPointsColumns._ID)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return cursor.getLong(cursor.getColumnIndexOrThrow(TrackPointsColumns._ID));
|
return cursor.getLong(cursor.getColumnIndexOrThrow(TrackPointsColumns._ID));
|
||||||
@@ -744,8 +748,8 @@ public class ContentProviderUtils {
|
|||||||
* @param maxLocations maximum number of locations to return. -1 for no limit
|
* @param maxLocations maximum number of locations to return. -1 for no limit
|
||||||
* @param descending true to sort the result in descending order (latest location first)
|
* @param descending true to sort the result in descending order (latest location first)
|
||||||
*/
|
*/
|
||||||
public Cursor getTrackPointCursor(long trackId, long startTrackPointId, int maxLocations, boolean descending) {
|
public Cursor getTrackPointCursor(Track.Id trackId, long startTrackPointId, int maxLocations, boolean descending) {
|
||||||
if (trackId < 0) {
|
if (!trackId.isValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -754,10 +758,10 @@ public class ContentProviderUtils {
|
|||||||
if (startTrackPointId >= 0) {
|
if (startTrackPointId >= 0) {
|
||||||
String comparison = descending ? "<=" : ">=";
|
String comparison = descending ? "<=" : ">=";
|
||||||
selection = TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns._ID + comparison + "?";
|
selection = TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns._ID + comparison + "?";
|
||||||
selectionArgs = new String[]{Long.toString(trackId), Long.toString(startTrackPointId)};
|
selectionArgs = new String[]{Long.toString(trackId.getId()), Long.toString(startTrackPointId)};
|
||||||
} else {
|
} else {
|
||||||
selection = TrackPointsColumns.TRACKID + "=?";
|
selection = TrackPointsColumns.TRACKID + "=?";
|
||||||
selectionArgs = new String[]{Long.toString(trackId)};
|
selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
}
|
}
|
||||||
|
|
||||||
String sortOrder = TrackPointsColumns._ID;
|
String sortOrder = TrackPointsColumns._ID;
|
||||||
@@ -777,12 +781,12 @@ public class ContentProviderUtils {
|
|||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public TrackPoint getLastValidTrackPoint(long trackId) {
|
public TrackPoint getLastValidTrackPoint(Track.Id trackId) {
|
||||||
if (trackId < 0) {
|
if (!trackId.isValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns.LATITUDE + "<=" + MAX_LATITUDE + ")";
|
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns.LATITUDE + "<=" + MAX_LATITUDE + ")";
|
||||||
String[] selectionArgs = new String[]{Long.toString(trackId)};
|
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
return findTrackPointBy(selection, selectionArgs);
|
return findTrackPointBy(selection, selectionArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -793,19 +797,19 @@ public class ContentProviderUtils {
|
|||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
* @return the content provider URI of the inserted trackPoint
|
* @return the content provider URI of the inserted trackPoint
|
||||||
*/
|
*/
|
||||||
public Uri insertTrackPoint(TrackPoint trackPoint, long trackId) {
|
public Uri insertTrackPoint(TrackPoint trackPoint, Track.Id trackId) {
|
||||||
return contentResolver.insert(TrackPointsColumns.CONTENT_URI_BY_ID, createContentValues(trackPoint, trackId));
|
return contentResolver.insert(TrackPointsColumns.CONTENT_URI_BY_ID, createContentValues(trackPoint, trackId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the {@link ContentValues} for a {@link TrackPoint}.
|
* Creates the {@link ContentValues} for a {@link TrackPoint}.
|
||||||
*
|
*
|
||||||
* @param trackPoint the trackPoint
|
* @param trackPoint the trackPointstats_pace_km#87
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
private ContentValues createContentValues(TrackPoint trackPoint, long trackId) {
|
private ContentValues createContentValues(TrackPoint trackPoint, Track.Id trackId) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(TrackPointsColumns.TRACKID, trackId);
|
values.put(TrackPointsColumns.TRACKID, trackId.getId());
|
||||||
values.put(TrackPointsColumns.LONGITUDE, (int) (trackPoint.getLongitude() * 1E6));
|
values.put(TrackPointsColumns.LONGITUDE, (int) (trackPoint.getLongitude() * 1E6));
|
||||||
values.put(TrackPointsColumns.LATITUDE, (int) (trackPoint.getLatitude() * 1E6));
|
values.put(TrackPointsColumns.LATITUDE, (int) (trackPoint.getLatitude() * 1E6));
|
||||||
|
|
||||||
@@ -846,7 +850,7 @@ public class ContentProviderUtils {
|
|||||||
* @param startTrackPointId the starting trackPoint id. -1L to ignore
|
* @param startTrackPointId the starting trackPoint id. -1L to ignore
|
||||||
* @param descending true to sort the result in descending order (latest location first)
|
* @param descending true to sort the result in descending order (latest location first)
|
||||||
*/
|
*/
|
||||||
public TrackPointIterator getTrackPointLocationIterator(final long trackId, final long startTrackPointId, final boolean descending) {
|
public TrackPointIterator getTrackPointLocationIterator(final Track.Id trackId, final long startTrackPointId, final boolean descending) {
|
||||||
return new TrackPointIterator(this, trackId, startTrackPointId, descending);
|
return new TrackPointIterator(this, trackId, startTrackPointId, descending);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,7 +876,7 @@ public class ContentProviderUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public List<TrackPoint> getTrackPoints(long trackId) {
|
public List<TrackPoint> getTrackPoints(Track.Id trackId) {
|
||||||
List<TrackPoint> trackPoints = null;
|
List<TrackPoint> trackPoints = null;
|
||||||
|
|
||||||
try (Cursor trackPointCursor = getTrackPointCursor(trackId, -1L, -1, false)) {
|
try (Cursor trackPointCursor = getTrackPointCursor(trackId, -1L, -1, false)) {
|
||||||
@@ -903,13 +907,23 @@ public class ContentProviderUtils {
|
|||||||
this.defaultCursorBatchSize = defaultCursorBatchSize;
|
this.defaultCursorBatchSize = defaultCursorBatchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String formatIdListForUri(Track.Id... trackIds) {
|
||||||
|
long[] ids = new long[trackIds.length];
|
||||||
|
for (int i = 0; i < trackIds.length; i++) {
|
||||||
|
ids[i] = trackIds[i].getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatIdListForUri(ids);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats an array of IDs as comma separated string value
|
* Formats an array of IDs as comma separated string value
|
||||||
*
|
*
|
||||||
* @param ids array with IDs
|
* @param ids array with IDs
|
||||||
* @return comma separated list of ids
|
* @return comma separated list of ids
|
||||||
*/
|
*/
|
||||||
public static String formatIdListForUri(long[] ids) {
|
private static String formatIdListForUri(long[] ids) {
|
||||||
StringBuilder idsPathSegment = new StringBuilder();
|
StringBuilder idsPathSegment = new StringBuilder();
|
||||||
for (long id : ids) {
|
for (long id : ids) {
|
||||||
if (idsPathSegment.length() > 0) {
|
if (idsPathSegment.length() > 0) {
|
||||||
|
|||||||
+18
-18
@@ -33,9 +33,9 @@ import android.util.Log;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
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 waypoints tables.
|
||||||
@@ -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.ordinal());
|
||||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.CONTENT_URI.getPath() + "/*", UrlType.TRACKS_BY_ID.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, MarkerColumns.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, MarkerColumns.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_BY_TRACKID.getPath() + "/*", UrlType.WAYPOINTS_BY_TRACKID.ordinal());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,7 +101,7 @@ public class CustomContentProvider extends ContentProvider {
|
|||||||
shouldVacuum = true;
|
shouldVacuum = true;
|
||||||
break;
|
break;
|
||||||
case WAYPOINTS:
|
case WAYPOINTS:
|
||||||
table = WaypointsColumns.TABLE_NAME;
|
table = MarkerColumns.TABLE_NAME;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown URL " + url);
|
throw new IllegalArgumentException("Unknown URL " + url);
|
||||||
@@ -139,10 +139,10 @@ public class CustomContentProvider extends ContentProvider {
|
|||||||
case TRACKS_BY_ID:
|
case TRACKS_BY_ID:
|
||||||
return TracksColumns.CONTENT_ITEMTYPE;
|
return TracksColumns.CONTENT_ITEMTYPE;
|
||||||
case WAYPOINTS:
|
case WAYPOINTS:
|
||||||
return WaypointsColumns.CONTENT_TYPE;
|
return MarkerColumns.CONTENT_TYPE;
|
||||||
case WAYPOINTS_BY_ID:
|
case WAYPOINTS_BY_ID:
|
||||||
case WAYPOINTS_BY_TRACKID:
|
case WAYPOINTS_BY_TRACKID:
|
||||||
return WaypointsColumns.CONTENT_ITEMTYPE;
|
return MarkerColumns.CONTENT_ITEMTYPE;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown URL " + url);
|
throw new IllegalArgumentException("Unknown URL " + url);
|
||||||
}
|
}
|
||||||
@@ -214,16 +214,16 @@ public class CustomContentProvider extends ContentProvider {
|
|||||||
queryBuilder.appendWhere(TracksColumns._ID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
queryBuilder.appendWhere(TracksColumns._ID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
||||||
break;
|
break;
|
||||||
case WAYPOINTS:
|
case WAYPOINTS:
|
||||||
queryBuilder.setTables(WaypointsColumns.TABLE_NAME);
|
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||||
sortOrder = sort != null ? sort : WaypointsColumns.DEFAULT_SORT_ORDER;
|
sortOrder = sort != null ? sort : MarkerColumns.DEFAULT_SORT_ORDER;
|
||||||
break;
|
break;
|
||||||
case WAYPOINTS_BY_ID:
|
case WAYPOINTS_BY_ID:
|
||||||
queryBuilder.setTables(WaypointsColumns.TABLE_NAME);
|
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||||
queryBuilder.appendWhere(WaypointsColumns._ID + "=" + ContentUris.parseId(url));
|
queryBuilder.appendWhere(MarkerColumns._ID + "=" + ContentUris.parseId(url));
|
||||||
break;
|
break;
|
||||||
case WAYPOINTS_BY_TRACKID:
|
case WAYPOINTS_BY_TRACKID:
|
||||||
queryBuilder.setTables(WaypointsColumns.TABLE_NAME);
|
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||||
queryBuilder.appendWhere(WaypointsColumns.TRACKID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
queryBuilder.appendWhere(MarkerColumns.TRACKID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown url " + url);
|
throw new IllegalArgumentException("Unknown url " + url);
|
||||||
@@ -262,12 +262,12 @@ public class CustomContentProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WAYPOINTS:
|
case WAYPOINTS:
|
||||||
table = WaypointsColumns.TABLE_NAME;
|
table = MarkerColumns.TABLE_NAME;
|
||||||
whereClause = where;
|
whereClause = where;
|
||||||
break;
|
break;
|
||||||
case WAYPOINTS_BY_ID:
|
case WAYPOINTS_BY_ID:
|
||||||
table = WaypointsColumns.TABLE_NAME;
|
table = MarkerColumns.TABLE_NAME;
|
||||||
whereClause = WaypointsColumns._ID + "=" + ContentUris.parseId(url);
|
whereClause = MarkerColumns._ID + "=" + ContentUris.parseId(url);
|
||||||
if (!TextUtils.isEmpty(where)) {
|
if (!TextUtils.isEmpty(where)) {
|
||||||
whereClause += " AND (" + where + ")";
|
whereClause += " AND (" + where + ")";
|
||||||
}
|
}
|
||||||
@@ -368,9 +368,9 @@ public class CustomContentProvider extends ContentProvider {
|
|||||||
* @param contentValues the content values
|
* @param contentValues the content values
|
||||||
*/
|
*/
|
||||||
private Uri insertWaypoint(Uri url, ContentValues contentValues) {
|
private Uri insertWaypoint(Uri url, ContentValues contentValues) {
|
||||||
long rowId = db.insert(WaypointsColumns.TABLE_NAME, WaypointsColumns._ID, contentValues);
|
long rowId = db.insert(MarkerColumns.TABLE_NAME, MarkerColumns._ID, contentValues);
|
||||||
if (rowId >= 0) {
|
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 waypoint " + url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
|
|
||||||
import java.util.UUID;
|
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.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
|
||||||
import de.dennisguse.opentracks.util.UUIDUtils;
|
import de.dennisguse.opentracks.util.UUIDUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,8 +52,8 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(TracksColumns.CREATE_TABLE);
|
db.execSQL(TracksColumns.CREATE_TABLE);
|
||||||
db.execSQL(TracksColumns.CREATE_TABLE_INDEX);
|
db.execSQL(TracksColumns.CREATE_TABLE_INDEX);
|
||||||
|
|
||||||
db.execSQL(WaypointsColumns.CREATE_TABLE);
|
db.execSQL(MarkerColumns.CREATE_TABLE);
|
||||||
db.execSQL(WaypointsColumns.CREATE_TABLE_INDEX);
|
db.execSQL(MarkerColumns.CREATE_TABLE_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -162,7 +163,7 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
int trackIdIndex = cursor.getColumnIndexOrThrow("_id");
|
int trackIdIndex = cursor.getColumnIndexOrThrow("_id");
|
||||||
do {
|
do {
|
||||||
long trackId = cursor.getLong(trackIdIndex);
|
Track.Id trackId = new Track.Id(cursor.getLong(trackIdIndex));
|
||||||
ContentValues cv = new ContentValues();
|
ContentValues cv = new ContentValues();
|
||||||
cv.put("uuid", UUIDUtils.toBytes(UUID.randomUUID()));
|
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)});
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ import androidx.annotation.Nullable;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.android.IContentResolver;
|
import de.dennisguse.opentracks.android.IContentResolver;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
@@ -29,9 +32,9 @@ import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
|||||||
/**
|
/**
|
||||||
* A content provider that mimics the behavior of {@link androidx.core.content.FileProvider}, which shares virtual (non-existing) KML-files.
|
* A content provider that mimics the behavior of {@link androidx.core.content.FileProvider}, which shares virtual (non-existing) KML-files.
|
||||||
* The actual content of the virtual files is generated by using the functionality defined in {@link CustomContentProvider}.
|
* The actual content of the virtual files is generated by using the functionality defined in {@link CustomContentProvider}.
|
||||||
*
|
* <p>
|
||||||
* Moreover, it manages access to OpenTrack's database via {@link CustomContentProvider}.
|
* Moreover, it manages access to OpenTrack's database via {@link CustomContentProvider}.
|
||||||
*
|
* <p>
|
||||||
* Explanation:
|
* Explanation:
|
||||||
* Although a request is handled by a {@link android.content.ContentProvider} (with temporarily granted permission), Android's security infrastructure prevents forwarding queries to non-exported {@link android.content.ContentProvider}.
|
* Although a request is handled by a {@link android.content.ContentProvider} (with temporarily granted permission), Android's security infrastructure prevents forwarding queries to non-exported {@link android.content.ContentProvider}.
|
||||||
* Thus, if {@link ShareContentProvider} and {@link CustomContentProvider} would be two different instances, the data would not be accessible to external apps.
|
* Thus, if {@link ShareContentProvider} and {@link CustomContentProvider} would be two different instances, the data would not be accessible to external apps.
|
||||||
@@ -70,14 +73,20 @@ public class ShareContentProvider extends CustomContentProvider implements ICont
|
|||||||
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES.getName() + "/*/*", URI_KMZ_WITH_TRACKDETAIL_SENSORDATA_AND_PICTURES);
|
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES.getName() + "/*/*", URI_KMZ_WITH_TRACKDETAIL_SENSORDATA_AND_PICTURES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pair<Uri, String> createURI(long[] trackIds, String trackName, @NonNull TrackFileFormat trackFileFormat) {
|
public static Pair<Uri, String> createURI(Track.Id trackId, String trackName, @NonNull TrackFileFormat trackFileFormat) {
|
||||||
if (trackIds.length == 0) {
|
Set<Track.Id> trackIds = new HashSet<>(1);
|
||||||
|
trackIds.add(trackId);
|
||||||
|
return createURI(trackIds, trackName, trackFileFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pair<Uri, String> createURI(Set<Track.Id> trackIds, String trackName, @NonNull TrackFileFormat trackFileFormat) {
|
||||||
|
if (trackIds.size() == 0) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder trackIdBuilder = new StringBuilder();
|
StringBuilder trackIdBuilder = new StringBuilder();
|
||||||
for (long trackId : trackIds) {
|
for (Track.Id trackId : trackIds) {
|
||||||
trackIdBuilder.append(trackId).append(TRACKID_DELIMITER);
|
trackIdBuilder.append(trackId.getId()).append(TRACKID_DELIMITER);
|
||||||
}
|
}
|
||||||
trackIdBuilder.deleteCharAt(trackIdBuilder.lastIndexOf(TRACKID_DELIMITER));
|
trackIdBuilder.deleteCharAt(trackIdBuilder.lastIndexOf(TRACKID_DELIMITER));
|
||||||
|
|
||||||
@@ -89,18 +98,18 @@ public class ShareContentProvider extends CustomContentProvider implements ICont
|
|||||||
return new Pair<>(uri, mime);
|
return new Pair<>(uri, mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long[] parseURI(Uri uri) {
|
static Set<Track.Id> parseURI(Uri uri) {
|
||||||
List<String> uriPaths = uri.getPathSegments();
|
List<String> uriPaths = uri.getPathSegments();
|
||||||
if (uriPaths == null || uriPaths.size() < 3) {
|
if (uriPaths == null || uriPaths.size() < 3) {
|
||||||
Log.d(TAG, "URI does not contain any trackIds.");
|
Log.d(TAG, "URI does not contain any trackIds.");
|
||||||
return new long[]{};
|
return new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] uriTrackIds = uriPaths.get(2).split(TRACKID_DELIMITER);
|
String[] uriTrackIds = uriPaths.get(2).split(TRACKID_DELIMITER);
|
||||||
|
|
||||||
long[] trackIds = new long[uriTrackIds.length];
|
Set<Track.Id> trackIds = new HashSet<>();
|
||||||
for (int i = 0; i < trackIds.length; i++) {
|
for (String uriTrackId : uriTrackIds) {
|
||||||
trackIds[i] = Long.parseLong(uriTrackIds[i]);
|
trackIds.add(new Track.Id(Long.parseLong(uriTrackId)));
|
||||||
}
|
}
|
||||||
return trackIds;
|
return trackIds;
|
||||||
}
|
}
|
||||||
@@ -202,17 +211,17 @@ public class ShareContentProvider extends CustomContentProvider implements ICont
|
|||||||
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
|
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
||||||
|
|
||||||
long[] trackIds = parseURI(uri);
|
Set<Track.Id> trackIds = parseURI(uri);
|
||||||
final Track[] tracks = new Track[trackIds.length];
|
final ArrayList<Track> tracks = new ArrayList<>();
|
||||||
for (int i = 0; i < trackIds.length; i++) {
|
for (Track.Id trackId : trackIds) {
|
||||||
tracks[i] = contentProviderUtils.getTrack(trackIds[i]);
|
tracks.add(contentProviderUtils.getTrack(trackId));
|
||||||
}
|
}
|
||||||
|
|
||||||
final TrackExporter trackExporter = getTrackFileFormat(uri).newTrackExporter(getContext(), tracks);
|
final TrackExporter trackExporter = getTrackFileFormat(uri).newTrackExporter(getContext());
|
||||||
|
|
||||||
PipeDataWriter<String> pipeDataWriter = (output, uri1, mimeType, opts, args) -> {
|
PipeDataWriter<String> pipeDataWriter = (output, uri1, mimeType, opts, args) -> {
|
||||||
try (FileOutputStream fileOutputStream = new FileOutputStream(output.getFileDescriptor())) {
|
try (FileOutputStream fileOutputStream = new FileOutputStream(output.getFileDescriptor())) {
|
||||||
trackExporter.writeTrack(getContext(), fileOutputStream);
|
trackExporter.writeTrack(tracks.toArray(new Track[0]), fileOutputStream);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "there occurred an error while sharing a file: " + e);
|
Log.w(TAG, "there occurred an error while sharing a file: " + e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.util.Log;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,14 +17,14 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
|||||||
private static final String TAG = TrackPointIterator.class.getSimpleName();
|
private static final String TAG = TrackPointIterator.class.getSimpleName();
|
||||||
|
|
||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
private final long trackId;
|
private final Track.Id trackId;
|
||||||
private final boolean descending;
|
private final boolean descending;
|
||||||
private final CachedTrackPointsIndexes indexes;
|
private final CachedTrackPointsIndexes indexes;
|
||||||
private long lastTrackPointId = -1L;
|
private long lastTrackPointId = -1L;
|
||||||
private Cursor cursor;
|
private Cursor cursor;
|
||||||
|
|
||||||
|
|
||||||
public TrackPointIterator(ContentProviderUtils contentProviderUtils, long trackId, long startTrackPointId, boolean descending) {
|
public TrackPointIterator(ContentProviderUtils contentProviderUtils, Track.Id trackId, long startTrackPointId, boolean descending) {
|
||||||
this.contentProviderUtils = contentProviderUtils;
|
this.contentProviderUtils = contentProviderUtils;
|
||||||
this.trackId = trackId;
|
this.trackId = trackId;
|
||||||
this.descending = descending;
|
this.descending = descending;
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ import de.dennisguse.opentracks.chart.ChartPoint;
|
|||||||
import de.dennisguse.opentracks.chart.ChartView;
|
import de.dennisguse.opentracks.chart.ChartView;
|
||||||
import de.dennisguse.opentracks.content.TrackDataHub;
|
import de.dennisguse.opentracks.content.TrackDataHub;
|
||||||
import de.dennisguse.opentracks.content.TrackDataListener;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
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.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||||
import de.dennisguse.opentracks.util.LocationUtils;
|
import de.dennisguse.opentracks.util.LocationUtils;
|
||||||
@@ -242,21 +242,21 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearWaypoints() {
|
public void clearMarkers() {
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
chartView.clearWaypoints();
|
chartView.clearWaypoints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewWaypoint(Waypoint waypoint) {
|
public void onNewMarker(Marker marker) {
|
||||||
if (isResumed() && waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) {
|
if (isResumed() && marker != null && LocationUtils.isValidLocation(marker.getLocation())) {
|
||||||
chartView.addWaypoint(waypoint);
|
chartView.addWaypoint(marker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewWaypointsDone() {
|
public void onNewMarkersDone() {
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
runOnUiThread(updateChart);
|
runOnUiThread(updateChart);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import androidx.fragment.app.DialogFragment;
|
|||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.util.DialogUtils;
|
import de.dennisguse.opentracks.util.DialogUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,9 +45,9 @@ public class ConfirmDeleteDialogFragment extends DialogFragment {
|
|||||||
*
|
*
|
||||||
* @param trackIds list of track ids to delete.
|
* @param trackIds list of track ids to delete.
|
||||||
*/
|
*/
|
||||||
public static void showDialog(FragmentManager fragmentManager, long[] trackIds) {
|
public static void showDialog(FragmentManager fragmentManager, Track.Id... trackIds) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putLongArray(KEY_TRACK_IDS, trackIds);
|
bundle.putParcelableArray(KEY_TRACK_IDS, trackIds);
|
||||||
|
|
||||||
ConfirmDeleteDialogFragment deleteTrackDialogFragment = new ConfirmDeleteDialogFragment();
|
ConfirmDeleteDialogFragment deleteTrackDialogFragment = new ConfirmDeleteDialogFragment();
|
||||||
deleteTrackDialogFragment.setArguments(bundle);
|
deleteTrackDialogFragment.setArguments(bundle);
|
||||||
@@ -66,7 +67,7 @@ public class ConfirmDeleteDialogFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
final long[] trackIds = getArguments().getLongArray(KEY_TRACK_IDS);
|
final Track.Id[] trackIds = (Track.Id[]) getArguments().getParcelableArray(KEY_TRACK_IDS);
|
||||||
|
|
||||||
int titleId = trackIds.length > 1 ? R.string.generic_delete_selected_confirm_title : R.string.track_delete_one_confirm_title;
|
int titleId = trackIds.length > 1 ? R.string.generic_delete_selected_confirm_title : R.string.track_delete_one_confirm_title;
|
||||||
int messageId = trackIds.length > 1 ? R.string.track_delete_multiple_confirm_message : R.string.track_delete_one_confirm_message;
|
int messageId = trackIds.length > 1 ? R.string.track_delete_multiple_confirm_message : R.string.track_delete_one_confirm_message;
|
||||||
@@ -85,6 +86,6 @@ public class ConfirmDeleteDialogFragment extends DialogFragment {
|
|||||||
*/
|
*/
|
||||||
public interface ConfirmDeleteCaller {
|
public interface ConfirmDeleteCaller {
|
||||||
|
|
||||||
void onConfirmDeleteDone(long[] trackIds);
|
void onConfirmDeleteDone(Track.Id... trackIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.util.DialogUtils;
|
import de.dennisguse.opentracks.util.DialogUtils;
|
||||||
|
|
||||||
@@ -41,9 +42,9 @@ public class DeleteMarkerDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
private DeleteMarkerCaller caller;
|
private DeleteMarkerCaller caller;
|
||||||
|
|
||||||
public static void showDialog(FragmentManager fragmentManager, long[] markerIds) {
|
public static void showDialog(FragmentManager fragmentManager, Marker.Id... waypointIds) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putLongArray(KEY_MARKER_IDS, markerIds);
|
bundle.putParcelableArray(KEY_MARKER_IDS, waypointIds);
|
||||||
|
|
||||||
DeleteMarkerDialogFragment deleteMarkerDialogFragment = new DeleteMarkerDialogFragment();
|
DeleteMarkerDialogFragment deleteMarkerDialogFragment = new DeleteMarkerDialogFragment();
|
||||||
deleteMarkerDialogFragment.setArguments(bundle);
|
deleteMarkerDialogFragment.setArguments(bundle);
|
||||||
@@ -63,12 +64,12 @@ public class DeleteMarkerDialogFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
final long[] markerIds = getArguments().getLongArray(KEY_MARKER_IDS);
|
final Marker.Id[] markerIds = (Marker.Id[]) getArguments().getParcelableArray(KEY_MARKER_IDS);
|
||||||
|
|
||||||
final FragmentActivity fragmentActivity = getActivity();
|
final FragmentActivity fragmentActivity = getActivity();
|
||||||
int titleId;
|
int titleId;
|
||||||
int messageId;
|
int messageId;
|
||||||
if (markerIds.length == 1 && markerIds[0] == -1L) {
|
if (markerIds == null) {
|
||||||
titleId = R.string.generic_delete_all_confirm_title;
|
titleId = R.string.generic_delete_all_confirm_title;
|
||||||
messageId = R.string.marker_delete_all_confirm_message;
|
messageId = R.string.marker_delete_all_confirm_message;
|
||||||
} else {
|
} else {
|
||||||
@@ -78,8 +79,8 @@ public class DeleteMarkerDialogFragment extends DialogFragment {
|
|||||||
return DialogUtils.createConfirmationDialog(
|
return DialogUtils.createConfirmationDialog(
|
||||||
fragmentActivity, titleId, getString(messageId), (dialog, which) -> new Thread(() -> {
|
fragmentActivity, titleId, getString(messageId), (dialog, which) -> new Thread(() -> {
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(fragmentActivity);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(fragmentActivity);
|
||||||
for (long markerId : markerIds) {
|
for (Marker.Id markerId : markerIds) {
|
||||||
contentProviderUtils.deleteWaypoint(getContext(), markerId);
|
contentProviderUtils.deleteMarker(getContext(), markerId);
|
||||||
}
|
}
|
||||||
caller.onDeleteMarkerDone();
|
caller.onDeleteMarkerDone();
|
||||||
}).start());
|
}).start());
|
||||||
|
|||||||
@@ -206,10 +206,10 @@ public class ExportProgressDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Boolean exportTrack(Context context, Track track) {
|
private Boolean exportTrack(Context context, Track track) {
|
||||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context, new Track[]{track});
|
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
||||||
|
|
||||||
//TODO Move to helper function
|
//TODO Move to helper function
|
||||||
String fileName = track.getId() + "." + trackFileFormat.getExtension();
|
String fileName = track.getId().getId() + "." + trackFileFormat.getExtension();
|
||||||
|
|
||||||
// Overwrite a file if it exists; DocumentFile.createFile() creates a new file appending a suffix if the displayname already exists.
|
// 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);
|
DocumentFile file = directory.findFile(fileName);
|
||||||
@@ -218,7 +218,7 @@ public class ExportProgressDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(file.getUri())) {
|
try (OutputStream outputStream = context.getContentResolver().openOutputStream(file.getUri())) {
|
||||||
if (trackExporter.writeTrack(context, outputStream)) {
|
if (trackExporter.writeTrack(track, outputStream)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (!file.delete()) {
|
if (!file.delete()) {
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ public class ImportProgressDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try (InputStream inputStream = context.getContentResolver().openInputStream(file.getUri())) {
|
try (InputStream inputStream = context.getContentResolver().openInputStream(file.getUri())) {
|
||||||
return trackImporter.importFile(inputStream) != -1L;
|
return trackImporter.importFile(inputStream) != null;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Unable to import file", e);
|
Log.e(TAG, "Unable to import file", e);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package de.dennisguse.opentracks.fragments;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
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.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel;
|
||||||
|
import de.dennisguse.opentracks.views.IntervalListView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fragment to display the intervals from recorded track.
|
||||||
|
*/
|
||||||
|
public class IntervalsRecordedFragment extends Fragment implements IntervalListView.IntervalListListener {
|
||||||
|
|
||||||
|
private static final String TAG = IntervalsRecordedFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final String TRACK_ID_KEY = "trackId";
|
||||||
|
|
||||||
|
private IntervalStatisticsModel viewModel;
|
||||||
|
private IntervalListView intervalListView;
|
||||||
|
|
||||||
|
private Track.Id trackId;
|
||||||
|
|
||||||
|
public static Fragment newInstance(Track.Id trackId) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putParcelable(TRACK_ID_KEY, trackId);
|
||||||
|
|
||||||
|
Fragment fragment = new IntervalsRecordedFragment();
|
||||||
|
fragment.setArguments(bundle);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.intervals_recording, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
|
trackId = getArguments().getParcelable(TRACK_ID_KEY);
|
||||||
|
|
||||||
|
intervalListView = new IntervalListView(getActivity(), this);
|
||||||
|
intervalListView.setId(View.generateViewId());
|
||||||
|
LinearLayout linearLayout = view.findViewById(R.id.root_view);
|
||||||
|
linearLayout.removeAllViews();
|
||||||
|
linearLayout.addView(intervalListView);
|
||||||
|
|
||||||
|
viewModel = new ViewModelProvider(this).get(IntervalStatisticsModel.class);
|
||||||
|
|
||||||
|
intervalChanged(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
intervalListView.destroy();
|
||||||
|
intervalListView = null;
|
||||||
|
viewModel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update intervals through {@link IntervalStatisticsModel} view model.
|
||||||
|
*
|
||||||
|
* @param interval intervals will split in this interval if not null. If it's null then view model will use the default one.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void intervalChanged(@Nullable IntervalStatisticsModel.IntervalOption interval) {
|
||||||
|
if (viewModel == null || intervalListView == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveData<IntervalStatistics> liveData = viewModel.getIntervalStats(trackId, interval);
|
||||||
|
liveData.observe(getActivity(), intervalStatistics -> {
|
||||||
|
if (intervalStatistics != null) {
|
||||||
|
intervalListView.display(intervalStatistics.getIntervalList());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unitChanged() {
|
||||||
|
if (viewModel != null) {
|
||||||
|
LiveData<IntervalStatistics> liveData = viewModel.getIntervalStats(trackId, null);
|
||||||
|
liveData.observe(getActivity(), intervalStatistics -> {
|
||||||
|
if (intervalStatistics != null) {
|
||||||
|
intervalListView.display(intervalStatistics.getIntervalList());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
package de.dennisguse.opentracks.fragments;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
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.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.util.UnitConversions;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel;
|
||||||
|
import de.dennisguse.opentracks.views.IntervalListView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fragment to display the intervals from recording track.
|
||||||
|
*/
|
||||||
|
public class IntervalsRecordingFragment extends Fragment implements IntervalListView.IntervalListListener, TrackRecordingActivity.OnTrackIdListener {
|
||||||
|
|
||||||
|
private static final String TAG = IntervalsRecordingFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final String TRACK_ID_KEY = "trackId";
|
||||||
|
|
||||||
|
// 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 IntervalStatisticsModel viewModel;
|
||||||
|
private IntervalListView.IntervalReverseListView intervalListView;
|
||||||
|
private IntervalStatisticsModel.IntervalOption selectedInterval;
|
||||||
|
|
||||||
|
private Track.Id trackId;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Runnable intervalRunner = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (isResumed()) {
|
||||||
|
updateIntervals();
|
||||||
|
intervalHandler.postDelayed(intervalRunner, UI_UPDATE_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Handler intervalHandler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.intervals_recording, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
|
trackId = getArguments().getParcelable(TRACK_ID_KEY);
|
||||||
|
((TrackRecordingActivity) getActivity()).setTrackIdListener(this);
|
||||||
|
|
||||||
|
intervalHandler = new Handler();
|
||||||
|
|
||||||
|
intervalListView = new IntervalListView.IntervalReverseListView(getActivity(), this);
|
||||||
|
intervalListView.setId(View.generateViewId());
|
||||||
|
LinearLayout linearLayout = view.findViewById(R.id.root_view);
|
||||||
|
linearLayout.removeAllViews();
|
||||||
|
linearLayout.addView(intervalListView);
|
||||||
|
|
||||||
|
viewModel = new ViewModelProvider(this).get(IntervalStatisticsModel.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
intervalHandler.post(intervalRunner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
intervalHandler.removeCallbacks(intervalRunner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
intervalListView.destroy();
|
||||||
|
intervalListView = null;
|
||||||
|
viewModel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update intervals through {@link IntervalStatisticsModel} view model.
|
||||||
|
*
|
||||||
|
* @param interval intervals will split in this interval if not null. If it's null then view model will use the default one.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void intervalChanged(@Nullable IntervalStatisticsModel.IntervalOption interval) {
|
||||||
|
if (viewModel == null || intervalListView == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedInterval = interval;
|
||||||
|
LiveData<IntervalStatistics> liveData = viewModel.getIntervalStats(trackId, interval);
|
||||||
|
liveData.observe(getActivity(), intervalStatistics -> {
|
||||||
|
if (intervalStatistics != null) {
|
||||||
|
intervalListView.display(intervalStatistics.getIntervalList());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateIntervals() {
|
||||||
|
intervalChanged(selectedInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unitChanged() {
|
||||||
|
if (viewModel != null) {
|
||||||
|
LiveData<IntervalStatistics> liveData = viewModel.getIntervalStats(trackId, selectedInterval);
|
||||||
|
liveData.observe(getActivity(), intervalStatistics -> {
|
||||||
|
if (intervalStatistics != null) {
|
||||||
|
intervalListView.display(intervalStatistics.getIntervalList());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTrackId(Track.Id trackId) {
|
||||||
|
this.trackId = trackId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.MarkerEditActivity;
|
import de.dennisguse.opentracks.MarkerEditActivity;
|
||||||
import de.dennisguse.opentracks.R;
|
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.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.util.IntentUtils;
|
import de.dennisguse.opentracks.util.IntentUtils;
|
||||||
import de.dennisguse.opentracks.util.ListItemUtils;
|
import de.dennisguse.opentracks.util.ListItemUtils;
|
||||||
@@ -67,7 +67,7 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
private ImageView photoView;
|
private ImageView photoView;
|
||||||
private ImageView textGradient;
|
private ImageView textGradient;
|
||||||
private LinearLayout waypointInfo;
|
private LinearLayout waypointInfo;
|
||||||
private Waypoint waypoint;
|
private Marker waypoint;
|
||||||
private final Runnable hideText = new Runnable() {
|
private final Runnable hideText = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -93,9 +93,9 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static MarkerDetailFragment newInstance(long markerId) {
|
public static MarkerDetailFragment newInstance(Marker.Id waypointId) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putLong(KEY_MARKER_ID, markerId);
|
bundle.putParcelable(KEY_MARKER_ID, waypointId);
|
||||||
|
|
||||||
MarkerDetailFragment fragment = new MarkerDetailFragment();
|
MarkerDetailFragment fragment = new MarkerDetailFragment();
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
@@ -106,8 +106,8 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
long markerId = getArguments().getLong(KEY_MARKER_ID);
|
Marker.Id waypointId = getArguments().getParcelable(KEY_MARKER_ID);
|
||||||
if (markerId == -1L) {
|
if (waypointId == null) {
|
||||||
Log.d(TAG, "invalid marker id");
|
Log.d(TAG, "invalid marker id");
|
||||||
getParentFragmentManager().popBackStack();
|
getParentFragmentManager().popBackStack();
|
||||||
return;
|
return;
|
||||||
@@ -182,7 +182,7 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
long markerId = getArguments().getLong(KEY_MARKER_ID);
|
Marker.Id waypointId = getArguments().getParcelable(KEY_MARKER_ID); //TODO Should only happen in onCreate?
|
||||||
FragmentActivity fragmentActivity = getActivity();
|
FragmentActivity fragmentActivity = getActivity();
|
||||||
Intent intent;
|
Intent intent;
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
@@ -191,7 +191,7 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
return true;
|
return true;
|
||||||
case R.id.marker_detail_edit:
|
case R.id.marker_detail_edit:
|
||||||
intent = IntentUtils.newIntent(fragmentActivity, MarkerEditActivity.class)
|
intent = IntentUtils.newIntent(fragmentActivity, MarkerEditActivity.class)
|
||||||
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
|
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, waypointId);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.marker_detail_share:
|
case R.id.marker_detail_share:
|
||||||
@@ -202,7 +202,7 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case R.id.marker_detail_delete:
|
case R.id.marker_detail_delete:
|
||||||
DeleteMarkerDialogFragment.showDialog(getChildFragmentManager(), new long[]{markerId});
|
DeleteMarkerDialogFragment.showDialog(getChildFragmentManager(), waypointId);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
@@ -216,7 +216,7 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
*/
|
*/
|
||||||
private void updateWaypoint(boolean refresh) {
|
private void updateWaypoint(boolean refresh) {
|
||||||
if (refresh || waypoint == null) {
|
if (refresh || waypoint == null) {
|
||||||
waypoint = contentProviderUtils.getWaypoint(getArguments().getLong(KEY_MARKER_ID));
|
waypoint = contentProviderUtils.getMarker(getArguments().getParcelable(KEY_MARKER_ID)); //TODO Should only happen in onCreate?
|
||||||
if (waypoint == null) {
|
if (waypoint == null) {
|
||||||
Log.d(TAG, "waypoint is null");
|
Log.d(TAG, "waypoint is null");
|
||||||
getParentFragmentManager().popBackStack();
|
getParentFragmentManager().popBackStack();
|
||||||
|
|||||||
@@ -33,11 +33,8 @@ import androidx.fragment.app.Fragment;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.TrackRecordedActivity;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
@@ -49,10 +46,13 @@ import de.dennisguse.opentracks.util.TrackIconUtils;
|
|||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
* @author Rodrigo Damazio
|
* @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 String category = "";
|
||||||
|
private Track track;
|
||||||
|
|
||||||
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (preferences, key) -> {
|
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)) {
|
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
|
||||||
@@ -71,7 +71,6 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
|||||||
return inflater.inflate(R.layout.statistics_recorded, container, false);
|
return inflater.inflate(R.layout.statistics_recorded, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Views */
|
|
||||||
private TextView totalTimeValueView;
|
private TextView totalTimeValueView;
|
||||||
private TextView distanceValue;
|
private TextView distanceValue;
|
||||||
private TextView distanceUnit;
|
private TextView distanceUnit;
|
||||||
@@ -88,6 +87,24 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
|||||||
private TextView speedMovingValue;
|
private TextView speedMovingValue;
|
||||||
private TextView speedMovingUnit;
|
private TextView speedMovingUnit;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
Track.Id trackId = getArguments().getParcelable(TRACK_ID_KEY);
|
||||||
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(getContext());
|
||||||
|
track = contentProviderUtils.getTrack(trackId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
@@ -140,23 +157,15 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
|||||||
super.onResume();
|
super.onResume();
|
||||||
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
|
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
|
||||||
|
|
||||||
TrackDataHub trackDataHub = ((TrackRecordedActivity) getActivity()).getTrackDataHub();
|
loadStatistics();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
|
|
||||||
|
PreferencesUtils.unregister(getContext(), sharedPreferenceChangeListener);
|
||||||
|
|
||||||
totalTimeValueView = null;
|
totalTimeValueView = null;
|
||||||
|
|
||||||
distanceValue = null;
|
distanceValue = null;
|
||||||
@@ -180,8 +189,7 @@ public class StatisticsRecordedFragment extends Fragment implements TrackDataLis
|
|||||||
speedMovingUnit = null;
|
speedMovingUnit = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void loadStatistics() {
|
||||||
public void onTrackUpdated(final Track track) {
|
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
getActivity().runOnUiThread(() -> {
|
getActivity().runOnUiThread(() -> {
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
@@ -193,41 +201,6 @@ 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() {
|
private void updateUI() {
|
||||||
String trackIconValue = TrackIconUtils.getIconValue(getContext(), category);
|
String trackIconValue = TrackIconUtils.getIconValue(getContext(), category);
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import de.dennisguse.opentracks.R;
|
|||||||
import de.dennisguse.opentracks.TrackRecordingActivity;
|
import de.dennisguse.opentracks.TrackRecordingActivity;
|
||||||
import de.dennisguse.opentracks.content.TrackDataHub;
|
import de.dennisguse.opentracks.content.TrackDataHub;
|
||||||
import de.dennisguse.opentracks.content.TrackDataListener;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
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.SensorDataCycling;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||||
@@ -55,13 +55,17 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
|||||||
|
|
||||||
private TrackRecordingServiceConnection trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
private TrackRecordingServiceConnection trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
||||||
|
|
||||||
private TrackPoint lastTrackPoint = null;
|
private TrackPoint lastTrackPoint;
|
||||||
private TrackStatistics lastTrackStatistics = null;
|
private TrackStatistics lastTrackStatistics;
|
||||||
|
|
||||||
private String category = "";
|
private String category = "";
|
||||||
@Deprecated //TODO This should be handled somewhere else; not in the UI.
|
@Deprecated //TODO This should be handled somewhere else; not in the UI.
|
||||||
private int recordingGpsAccuracy;
|
private int recordingGpsAccuracy;
|
||||||
|
|
||||||
|
public static Fragment newInstance() {
|
||||||
|
return new StatisticsRecordingFragment();
|
||||||
|
}
|
||||||
|
|
||||||
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||||
@@ -76,7 +80,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
|||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(getContext(), R.string.recording_track_id_key, key)) {
|
if (PreferencesUtils.isKey(getContext(), R.string.recording_track_id_key, key)) {
|
||||||
recordingGpsAccuracy = PreferencesUtils.getRecordingGPSAccuracy(getContext());
|
recordingGpsAccuracy = PreferencesUtils.getRecordingGPSAccuracy(getContext());
|
||||||
if (PreferencesUtils.getRecordingTrackId(getContext()) != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
if (PreferencesUtils.getRecordingTrackId(getContext()).isValid()) {
|
||||||
// A recording track id has been set -> Resumes track and starts timer.
|
// A recording track id has been set -> Resumes track and starts timer.
|
||||||
resumeTrackDataHub();
|
resumeTrackDataHub();
|
||||||
trackRecordingServiceConnection.startConnection(getContext());
|
trackRecordingServiceConnection.startConnection(getContext());
|
||||||
@@ -346,17 +350,17 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearWaypoints() {
|
public void clearMarkers() {
|
||||||
// We don't care.
|
// We don't care.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewWaypoint(Waypoint wpt) {
|
public void onNewMarker(Marker marker) {
|
||||||
// We don't care.
|
// We don't care.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewWaypointsDone() {
|
public void onNewMarkersDone() {
|
||||||
// We don't care.
|
// We don't care.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.content.Context;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.FileTrackExporter;
|
import de.dennisguse.opentracks.io.file.exporter.FileTrackExporter;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.GpxTrackWriter;
|
import de.dennisguse.opentracks.io.file.exporter.GpxTrackWriter;
|
||||||
@@ -21,8 +20,8 @@ public enum TrackFileFormat {
|
|||||||
|
|
||||||
KML_ONLY_TRACK {
|
KML_ONLY_TRACK {
|
||||||
@Override
|
@Override
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple) {
|
public TrackWriter newTrackWriter(Context context) {
|
||||||
return new KmlTrackWriter(context, multiple, false, false, false);
|
return new KmlTrackWriter(context, false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -36,8 +35,8 @@ public enum TrackFileFormat {
|
|||||||
},
|
},
|
||||||
KML_WITH_TRACKDETAIL {
|
KML_WITH_TRACKDETAIL {
|
||||||
@Override
|
@Override
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple) {
|
public TrackWriter newTrackWriter(Context context) {
|
||||||
return new KmlTrackWriter(context, multiple, true, false, false);
|
return new KmlTrackWriter(context, true, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -51,8 +50,8 @@ public enum TrackFileFormat {
|
|||||||
},
|
},
|
||||||
KML_WITH_TRACKDETAIL_AND_SENSORDATA {
|
KML_WITH_TRACKDETAIL_AND_SENSORDATA {
|
||||||
@Override
|
@Override
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple) {
|
public TrackWriter newTrackWriter(Context context) {
|
||||||
return new KmlTrackWriter(context, multiple, true, true, false);
|
return new KmlTrackWriter(context, true, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -69,12 +68,12 @@ public enum TrackFileFormat {
|
|||||||
private static final boolean exportPhotos = false;
|
private static final boolean exportPhotos = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple) {
|
public TrackWriter newTrackWriter(Context context) {
|
||||||
return new KmlTrackWriter(context, multiple, false, false, exportPhotos);
|
return new KmlTrackWriter(context, false, false, exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
|
public TrackExporter newTrackExporter(Context context) {
|
||||||
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, exportPhotos);
|
return newKmzTrackExporter(context, this.newTrackWriter(context), exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,12 +95,12 @@ public enum TrackFileFormat {
|
|||||||
private static final boolean exportPhotos = false;
|
private static final boolean exportPhotos = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple) {
|
public TrackWriter newTrackWriter(Context context) {
|
||||||
return new KmlTrackWriter(context, multiple, true, false, exportPhotos);
|
return new KmlTrackWriter(context, true, false, exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
|
public TrackExporter newTrackExporter(Context context) {
|
||||||
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, exportPhotos);
|
return newKmzTrackExporter(context, this.newTrackWriter(context), exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -124,8 +123,8 @@ public enum TrackFileFormat {
|
|||||||
private static final boolean exportPhotos = false;
|
private static final boolean exportPhotos = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple) {
|
public TrackWriter newTrackWriter(Context context) {
|
||||||
return new KmlTrackWriter(context, multiple, true, true, exportPhotos);
|
return new KmlTrackWriter(context, true, true, exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -133,8 +132,8 @@ public enum TrackFileFormat {
|
|||||||
return MIME_KMZ;
|
return MIME_KMZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
|
public TrackExporter newTrackExporter(Context context) {
|
||||||
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, exportPhotos);
|
return newKmzTrackExporter(context, this.newTrackWriter(context), exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getExtension() {
|
public String getExtension() {
|
||||||
@@ -153,8 +152,8 @@ public enum TrackFileFormat {
|
|||||||
private static final boolean exportPhotos = true;
|
private static final boolean exportPhotos = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple) {
|
public TrackWriter newTrackWriter(Context context) {
|
||||||
return new KmlTrackWriter(context, multiple, true, true, exportPhotos);
|
return new KmlTrackWriter(context, true, true, exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -162,8 +161,8 @@ public enum TrackFileFormat {
|
|||||||
return MIME_KMZ;
|
return MIME_KMZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
|
public TrackExporter newTrackExporter(Context context) {
|
||||||
return newKmzTrackExporter(context, newTrackWriter(context, tracks.length > 1), tracks, exportPhotos);
|
return newKmzTrackExporter(context, newTrackWriter(context), exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getExtension() {
|
public String getExtension() {
|
||||||
@@ -178,7 +177,7 @@ public enum TrackFileFormat {
|
|||||||
},
|
},
|
||||||
GPX {
|
GPX {
|
||||||
@Override
|
@Override
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple) {
|
public TrackWriter newTrackWriter(Context context) {
|
||||||
return new GpxTrackWriter(context.getString(R.string.app_name));
|
return new GpxTrackWriter(context.getString(R.string.app_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,12 +195,12 @@ public enum TrackFileFormat {
|
|||||||
|
|
||||||
private static final String MIME_KML = "application/vnd.google-earth.kml+xml";
|
private static final String MIME_KML = "application/vnd.google-earth.kml+xml";
|
||||||
|
|
||||||
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, Track[] tracks, boolean exportPhotos) {
|
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, boolean exportPhotos) {
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, trackWriter, tracks);
|
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, trackWriter);
|
||||||
|
|
||||||
return new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks, exportPhotos);
|
return new KmzTrackExporter(context, contentProviderUtils, fileTrackExporter, exportPhotos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -209,19 +208,18 @@ public enum TrackFileFormat {
|
|||||||
*/
|
*/
|
||||||
public abstract String getMimeType();
|
public abstract String getMimeType();
|
||||||
|
|
||||||
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
|
public TrackExporter newTrackExporter(Context context) {
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||||
TrackWriter trackWriter = newTrackWriter(context, tracks.length > 1);
|
TrackWriter trackWriter = newTrackWriter(context);
|
||||||
return new FileTrackExporter(contentProviderUtils, trackWriter, tracks);
|
return new FileTrackExporter(contentProviderUtils, trackWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new track writer for the format.
|
* Creates a new track writer for the format.
|
||||||
*
|
*
|
||||||
* @param context the context
|
* @param context the context
|
||||||
* @param multiple true for writing multiple tracks
|
|
||||||
*/
|
*/
|
||||||
public abstract TrackWriter newTrackWriter(Context context, boolean multiple);
|
public abstract TrackWriter newTrackWriter(Context context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the file extension for each format.
|
* Returns the file extension for each format.
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.io.file.exporter;
|
package de.dennisguse.opentracks.io.file.exporter;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -24,9 +23,9 @@ import androidx.annotation.NonNull;
|
|||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||||
import de.dennisguse.opentracks.util.LocationUtils;
|
import de.dennisguse.opentracks.util.LocationUtils;
|
||||||
@@ -42,7 +41,6 @@ public class FileTrackExporter implements TrackExporter {
|
|||||||
private static final String TAG = FileTrackExporter.class.getSimpleName();
|
private static final String TAG = FileTrackExporter.class.getSimpleName();
|
||||||
|
|
||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
private final Track[] tracks;
|
|
||||||
private final TrackWriter trackWriter;
|
private final TrackWriter trackWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,29 +48,37 @@ public class FileTrackExporter implements TrackExporter {
|
|||||||
*
|
*
|
||||||
* @param contentProviderUtils the content provider utils
|
* @param contentProviderUtils the content provider utils
|
||||||
* @param trackWriter the track writer
|
* @param trackWriter the track writer
|
||||||
* @param tracks the tracks
|
|
||||||
*/
|
*/
|
||||||
public FileTrackExporter(ContentProviderUtils contentProviderUtils, TrackWriter trackWriter, Track[] tracks) {
|
public FileTrackExporter(ContentProviderUtils contentProviderUtils, TrackWriter trackWriter) {
|
||||||
this.contentProviderUtils = contentProviderUtils;
|
this.contentProviderUtils = contentProviderUtils;
|
||||||
this.tracks = tracks;
|
|
||||||
this.trackWriter = trackWriter;
|
this.trackWriter = trackWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTrack(@NonNull Context context, @NonNull OutputStream outputStream) {
|
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||||
|
return writeTrack(new Track[]{track}, outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||||
try {
|
try {
|
||||||
trackWriter.prepare(outputStream);
|
trackWriter.prepare(outputStream);
|
||||||
trackWriter.writeHeader(tracks);
|
trackWriter.writeHeader(tracks);
|
||||||
for (Track track1 : tracks) {
|
for (Track track1 : tracks) {
|
||||||
writeWaypoints(track1);
|
writeWaypoints(track1);
|
||||||
}
|
}
|
||||||
trackWriter.writeBeginTracks();
|
boolean hasMultipleTracks = tracks.length > 1;
|
||||||
|
if (hasMultipleTracks) {
|
||||||
|
trackWriter.writeMultiTrackBegin();
|
||||||
|
}
|
||||||
long startTime = tracks[0].getTrackStatistics().getStartTime_ms();
|
long startTime = tracks[0].getTrackStatistics().getStartTime_ms();
|
||||||
for (Track track : tracks) {
|
for (Track track : tracks) {
|
||||||
long offset = track.getTrackStatistics().getStartTime_ms() - startTime;
|
long offset = track.getTrackStatistics().getStartTime_ms() - startTime;
|
||||||
writeLocations(track, offset);
|
writeLocations(track, offset);
|
||||||
}
|
}
|
||||||
trackWriter.writeEndTracks();
|
if (hasMultipleTracks) {
|
||||||
|
trackWriter.writeMultiTrackEnd();
|
||||||
|
}
|
||||||
trackWriter.writeFooter();
|
trackWriter.writeFooter();
|
||||||
trackWriter.close();
|
trackWriter.close();
|
||||||
|
|
||||||
@@ -92,7 +98,7 @@ public class FileTrackExporter implements TrackExporter {
|
|||||||
* 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.
|
* 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.
|
||||||
*/
|
*/
|
||||||
boolean hasWaypoints = false;
|
boolean hasWaypoints = false;
|
||||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(track.getId(), -1L, ContentProviderUtils.MAX_LOADED_WAYPOINTS_POINTS)) {
|
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, ContentProviderUtils.MAX_LOADED_MARKERS)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
for (int i = 0; i < cursor.getCount(); i++) {
|
for (int i = 0; i < cursor.getCount(); i++) {
|
||||||
if (Thread.interrupted()) {
|
if (Thread.interrupted()) {
|
||||||
@@ -102,7 +108,7 @@ public class FileTrackExporter implements TrackExporter {
|
|||||||
trackWriter.writeBeginWaypoints(track);
|
trackWriter.writeBeginWaypoints(track);
|
||||||
hasWaypoints = true;
|
hasWaypoints = true;
|
||||||
}
|
}
|
||||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursor);
|
Marker waypoint = contentProviderUtils.createMarker(cursor);
|
||||||
trackWriter.writeWaypoint(waypoint);
|
trackWriter.writeWaypoint(waypoint);
|
||||||
|
|
||||||
cursor.moveToNext();
|
cursor.moveToNext();
|
||||||
@@ -121,7 +127,6 @@ public class FileTrackExporter implements TrackExporter {
|
|||||||
boolean wroteTrack = false;
|
boolean wroteTrack = false;
|
||||||
boolean wroteSegment = false;
|
boolean wroteSegment = false;
|
||||||
boolean isLastLocationValid = false;
|
boolean isLastLocationValid = false;
|
||||||
int locationNumber = 0;
|
|
||||||
TrackPoint lastTrackPoint = null;
|
TrackPoint lastTrackPoint = null;
|
||||||
|
|
||||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), -1L, false)) {
|
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), -1L, false)) {
|
||||||
@@ -133,7 +138,6 @@ public class FileTrackExporter implements TrackExporter {
|
|||||||
TrackPoint trackPoint = trackPointIterator.next();
|
TrackPoint trackPoint = trackPointIterator.next();
|
||||||
|
|
||||||
setLocationTime(trackPoint, offset);
|
setLocationTime(trackPoint, offset);
|
||||||
locationNumber++;
|
|
||||||
|
|
||||||
boolean isLocationValid = LocationUtils.isValidLocation(trackPoint.getLocation());
|
boolean isLocationValid = LocationUtils.isValidLocation(trackPoint.getLocation());
|
||||||
boolean isSegmentValid = isLocationValid && isLastLocationValid;
|
boolean isSegmentValid = isLocationValid && isLastLocationValid;
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ import java.io.PrintWriter;
|
|||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,7 +130,7 @@ public class GpxTrackWriter implements TrackWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeWaypoint(Waypoint waypoint) {
|
public void writeWaypoint(Marker waypoint) {
|
||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
Location location = waypoint.getLocation();
|
Location location = waypoint.getLocation();
|
||||||
printWriter.println("<wpt " + formatLocation(location) + ">");
|
printWriter.println("<wpt " + formatLocation(location) + ">");
|
||||||
@@ -146,12 +146,12 @@ public class GpxTrackWriter implements TrackWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeBeginTracks() {
|
public void writeMultiTrackBegin() {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeEndTracks() {
|
public void writeMultiTrackEnd() {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ import java.util.List;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.DescriptionGenerator;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
@@ -57,7 +57,6 @@ public class KmlTrackWriter implements TrackWriter {
|
|||||||
private static final String TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png";
|
private static final String TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final boolean hasMultipleTracks;
|
|
||||||
private final boolean exportPhotos;
|
private final boolean exportPhotos;
|
||||||
private final boolean exportTrackDetail;
|
private final boolean exportTrackDetail;
|
||||||
private final boolean exportSensorData;
|
private final boolean exportSensorData;
|
||||||
@@ -74,14 +73,12 @@ public class KmlTrackWriter implements TrackWriter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context the context
|
* @param context the context
|
||||||
* @param hasMultipleTracks should encode multiple tracks into one file?
|
|
||||||
* @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, waypoints, timing)?
|
||||||
* @param exportSensorData should {@link TrackPoint}'s sensor data be exported?
|
* @param exportSensorData should {@link TrackPoint}'s sensor data be exported?
|
||||||
* @param exportPhotos should pictures be exported (if true: exports to KMZ)?
|
* @param exportPhotos should pictures be exported (if true: exports to KMZ)?
|
||||||
*/
|
*/
|
||||||
public KmlTrackWriter(Context context, boolean hasMultipleTracks, boolean exportTrackDetail, boolean exportSensorData, boolean exportPhotos) {
|
public KmlTrackWriter(Context context, boolean exportTrackDetail, boolean exportSensorData, boolean exportPhotos) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.hasMultipleTracks = hasMultipleTracks;
|
|
||||||
this.exportTrackDetail = exportTrackDetail;
|
this.exportTrackDetail = exportTrackDetail;
|
||||||
this.exportSensorData = exportSensorData;
|
this.exportSensorData = exportSensorData;
|
||||||
this.exportPhotos = exportPhotos;
|
this.exportPhotos = exportPhotos;
|
||||||
@@ -166,7 +163,7 @@ public class KmlTrackWriter implements TrackWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeWaypoint(Waypoint waypoint) {
|
public void writeWaypoint(Marker waypoint) {
|
||||||
if (printWriter != null && exportTrackDetail) {
|
if (printWriter != null && exportTrackDetail) {
|
||||||
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, waypoint.getTrackId(), waypoint.getPhotoURI()) != null;
|
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, waypoint.getTrackId(), waypoint.getPhotoURI()) != null;
|
||||||
if (waypoint.hasPhoto() && exportPhotos && existsPhoto) {
|
if (waypoint.hasPhoto() && exportPhotos && existsPhoto) {
|
||||||
@@ -178,18 +175,16 @@ public class KmlTrackWriter implements TrackWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void writeMultiTrackBegin() {
|
||||||
public void writeBeginTracks() {
|
if (printWriter != null) {
|
||||||
if (printWriter != null && hasMultipleTracks) {
|
|
||||||
printWriter.println("<Folder id=tour>");
|
printWriter.println("<Folder id=tour>");
|
||||||
printWriter.println("<name>" + context.getString(R.string.generic_tracks) + "</name>");
|
printWriter.println("<name>" + context.getString(R.string.generic_tracks) + "</name>");
|
||||||
printWriter.println("<open>1</open>");
|
printWriter.println("<open>1</open>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void writeMultiTrackEnd() {
|
||||||
public void writeEndTracks() {
|
if (printWriter != null) {
|
||||||
if (printWriter != null && hasMultipleTracks) {
|
|
||||||
printWriter.println("</Folder>");
|
printWriter.println("</Folder>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,7 +335,7 @@ public class KmlTrackWriter implements TrackWriter {
|
|||||||
* @param waypoint Waypoint object.
|
* @param waypoint Waypoint object.
|
||||||
* @param heading the heading.
|
* @param heading the heading.
|
||||||
*/
|
*/
|
||||||
private void writePhotoOverlay(Waypoint waypoint, float heading) {
|
private void writePhotoOverlay(Marker waypoint, float heading) {
|
||||||
if (exportTrackDetail) {
|
if (exportTrackDetail) {
|
||||||
printWriter.println("<PhotoOverlay>");
|
printWriter.println("<PhotoOverlay>");
|
||||||
printWriter.println("<name>" + StringUtils.formatCData(waypoint.getName()) + "</name>");
|
printWriter.println("<name>" + StringUtils.formatCData(waypoint.getName()) + "</name>");
|
||||||
@@ -393,7 +388,7 @@ public class KmlTrackWriter implements TrackWriter {
|
|||||||
* @param trackId the track id containing the location
|
* @param trackId the track id containing the location
|
||||||
* @param location the location
|
* @param location the location
|
||||||
*/
|
*/
|
||||||
private float getHeading(long trackId, Location location) {
|
private float getHeading(Track.Id trackId, Location location) {
|
||||||
long trackPointId = contentProviderUtils.getTrackPointId(trackId, location);
|
long trackPointId = contentProviderUtils.getTrackPointId(trackId, location);
|
||||||
if (trackPointId == -1L) {
|
if (trackPointId == -1L) {
|
||||||
return location.getBearing();
|
return location.getBearing();
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ import java.io.OutputStream;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
|
|
||||||
@@ -51,35 +51,37 @@ public class KmzTrackExporter implements TrackExporter {
|
|||||||
|
|
||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
private final FileTrackExporter fileTrackExporter;
|
private final FileTrackExporter fileTrackExporter;
|
||||||
private final Track[] tracks;
|
|
||||||
|
|
||||||
private final boolean exportPhotos;
|
private final boolean exportPhotos;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
* @param context the context
|
||||||
* @param contentProviderUtils the content provider utils
|
* @param contentProviderUtils the content provider utils
|
||||||
* @param trackExporter the file track exporter
|
* @param trackExporter the file track exporter
|
||||||
* @param tracks the tracks to export
|
|
||||||
*/
|
*/
|
||||||
public KmzTrackExporter(ContentProviderUtils contentProviderUtils, FileTrackExporter trackExporter, Track[] tracks, boolean exportPhotos) {
|
public KmzTrackExporter(Context context, ContentProviderUtils contentProviderUtils, FileTrackExporter trackExporter, boolean exportPhotos) {
|
||||||
|
this.context = context;
|
||||||
this.contentProviderUtils = contentProviderUtils;
|
this.contentProviderUtils = contentProviderUtils;
|
||||||
this.fileTrackExporter = trackExporter;
|
this.fileTrackExporter = trackExporter;
|
||||||
this.tracks = tracks;
|
|
||||||
this.exportPhotos = exportPhotos;
|
this.exportPhotos = exportPhotos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTrack(@NonNull Context context, @NonNull OutputStream outputStream) {
|
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||||
ZipOutputStream zipOutputStream = null;
|
return writeTrack(new Track[]{track}, outputStream);
|
||||||
try {
|
}
|
||||||
zipOutputStream = new ZipOutputStream(outputStream);
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||||
|
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
|
||||||
// Add kml file
|
// Add kml file
|
||||||
ZipEntry zipEntry = new ZipEntry(KMZ_KML_FILE);
|
ZipEntry zipEntry = new ZipEntry(KMZ_KML_FILE);
|
||||||
zipOutputStream.putNextEntry(zipEntry);
|
zipOutputStream.putNextEntry(zipEntry);
|
||||||
|
|
||||||
boolean success = fileTrackExporter.writeTrack(context, zipOutputStream);
|
boolean success = fileTrackExporter.writeTrack(tracks, zipOutputStream);
|
||||||
zipOutputStream.closeEntry();
|
zipOutputStream.closeEntry();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Log.e(TAG, "Unable to write kml in kmz");
|
Log.e(TAG, "Unable to write kml in kmz");
|
||||||
@@ -87,31 +89,23 @@ public class KmzTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add photos
|
// Add photos
|
||||||
if (exportPhotos) addImages(context, zipOutputStream);
|
if (exportPhotos) addImages(context, tracks ,zipOutputStream);
|
||||||
return true;
|
return true;
|
||||||
} catch (InterruptedException | IOException e) {
|
} catch (InterruptedException | IOException e) {
|
||||||
Log.e(TAG, "Unable to write track", e);
|
Log.e(TAG, "Unable to write track", e);
|
||||||
return false;
|
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, ZipOutputStream zipOutputStream) throws InterruptedException, IOException {
|
private void addImages(Context context, Track[] tracks, ZipOutputStream zipOutputStream) throws InterruptedException, IOException {
|
||||||
for (Track track : tracks) {
|
for (Track track : tracks) {
|
||||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(track.getId(), -1L, -1)) {
|
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, -1)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
for (int i = 0; i < cursor.getCount(); i++) {
|
for (int i = 0; i < cursor.getCount(); i++) {
|
||||||
if (Thread.interrupted()) {
|
if (Thread.interrupted()) {
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
}
|
}
|
||||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursor);
|
Marker waypoint = contentProviderUtils.createMarker(cursor);
|
||||||
if (waypoint.hasPhoto()) {
|
if (waypoint.hasPhoto()) {
|
||||||
Uri uriPhoto = waypoint.getPhotoURI();
|
Uri uriPhoto = waypoint.getPhotoURI();
|
||||||
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, track.getId(), uriPhoto) != null;
|
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, track.getId(), uriPhoto) != null;
|
||||||
@@ -127,7 +121,7 @@ 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 waypoint) throws IOException {
|
||||||
try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) {
|
try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) {
|
||||||
ZipEntry zipEntry = new ZipEntry(buildKmzImageFilePath(waypoint));
|
ZipEntry zipEntry = new ZipEntry(buildKmzImageFilePath(waypoint));
|
||||||
zipOutputStream.putNextEntry(zipEntry);
|
zipOutputStream.putNextEntry(zipEntry);
|
||||||
@@ -156,7 +150,7 @@ public class KmzTrackExporter implements TrackExporter {
|
|||||||
*
|
*
|
||||||
* @param waypoint Waypoint object.
|
* @param waypoint Waypoint object.
|
||||||
*/
|
*/
|
||||||
public static String buildKmzImageFilePath(Waypoint waypoint) {
|
public static String buildKmzImageFilePath(Marker waypoint) {
|
||||||
String ext = FileUtils.getExtension(waypoint.getPhotoUrl());
|
String ext = FileUtils.getExtension(waypoint.getPhotoUrl());
|
||||||
ext = ext == null ? "" : "." + ext;
|
ext = ext == null ? "" : "." + ext;
|
||||||
return KMZ_IMAGES_DIR + File.separatorChar + FileUtils.sanitizeFileName(waypoint.getId() + ext);
|
return KMZ_IMAGES_DIR + File.separatorChar + FileUtils.sanitizeFileName(waypoint.getId() + ext);
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.io.file.exporter;
|
package de.dennisguse.opentracks.io.file.exporter;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Track exporting for exporting track to an {@link OutputStream}.
|
* Track exporting for exporting track to an {@link OutputStream}.
|
||||||
*
|
*
|
||||||
@@ -29,12 +29,7 @@ import java.io.OutputStream;
|
|||||||
*/
|
*/
|
||||||
public interface TrackExporter {
|
public interface TrackExporter {
|
||||||
|
|
||||||
/**
|
boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream);
|
||||||
* Write track to an output stream.
|
|
||||||
* Depending on the implementation a context might be required.
|
boolean writeTrack(Track track, @NonNull OutputStream outputStream);
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param outputStream the output stream
|
|
||||||
*/
|
|
||||||
boolean writeTrack(@NonNull Context context, @NonNull OutputStream outputStream);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ package de.dennisguse.opentracks.io.file.exporter;
|
|||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
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:
|
* Interface for writing tracks to a file. The expected sequence of calls is:
|
||||||
@@ -30,9 +30,9 @@ import de.dennisguse.opentracks.content.data.Waypoint;
|
|||||||
* For each track:
|
* For each track:
|
||||||
* {@link #writeBeginWaypoints(Track)}
|
* {@link #writeBeginWaypoints(Track)}
|
||||||
* For each waypoint:
|
* For each waypoint:
|
||||||
* {@link #writeWaypoint(Waypoint)}
|
* {@link #writeWaypoint(Marker)}
|
||||||
* {@link #writeEndWaypoints()}
|
* {@link #writeEndWaypoints()}
|
||||||
* {@link #writeBeginTracks()}
|
* {@link #writeMultiTrackBegin()}
|
||||||
* For each track:
|
* For each track:
|
||||||
* {@link #writeBeginTrack(Track, TrackPoint)}
|
* {@link #writeBeginTrack(Track, TrackPoint)}
|
||||||
* For each segment:
|
* For each segment:
|
||||||
@@ -41,7 +41,7 @@ import de.dennisguse.opentracks.content.data.Waypoint;
|
|||||||
* {@link #writeTrackPoint(TrackPoint)}
|
* {@link #writeTrackPoint(TrackPoint)}
|
||||||
* {@link #writeCloseSegment()}
|
* {@link #writeCloseSegment()}
|
||||||
* {@link #writeEndTrack(Track, TrackPoint)}
|
* {@link #writeEndTrack(Track, TrackPoint)}
|
||||||
* {@link #writeEndTracks()}
|
* {@link #writeMultiTrackEnd()}
|
||||||
* {@link #writeFooter()}
|
* {@link #writeFooter()}
|
||||||
* {@link #close()}
|
* {@link #close()}
|
||||||
* </pre>
|
* </pre>
|
||||||
@@ -91,17 +91,17 @@ public interface TrackWriter {
|
|||||||
*
|
*
|
||||||
* @param waypoint the waypoint
|
* @param waypoint the waypoint
|
||||||
*/
|
*/
|
||||||
void writeWaypoint(Waypoint waypoint);
|
void writeWaypoint(Marker waypoint);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the beginning of the tracks.
|
* Writes the beginning of the tracks.
|
||||||
*/
|
*/
|
||||||
void writeBeginTracks();
|
void writeMultiTrackBegin();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the end of the tracks,
|
* Writes the end of the tracks,
|
||||||
*/
|
*/
|
||||||
void writeEndTracks();
|
void writeMultiTrackEnd();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the beginning of a track.
|
* Writes the beginning of a track.
|
||||||
|
|||||||
+17
-17
@@ -39,9 +39,9 @@ import javax.xml.parsers.SAXParser;
|
|||||||
import javax.xml.parsers.SAXParserFactory;
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||||
@@ -68,9 +68,9 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
private final int recordingDistanceInterval;
|
private final int recordingDistanceInterval;
|
||||||
|
|
||||||
private long importTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
private Track.Id importTrackId;
|
||||||
private final List<Long> trackIds = new ArrayList<>();
|
private final List<Track.Id> trackIds = new ArrayList<>();
|
||||||
private final List<Waypoint> waypoints = new ArrayList<>();
|
private final List<Marker> waypoints = new ArrayList<>();
|
||||||
|
|
||||||
// The current element content
|
// The current element content
|
||||||
//TODO Should be made private and getter be used by child classes.
|
//TODO Should be made private and getter be used by child classes.
|
||||||
@@ -104,7 +104,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
this.recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval(context);
|
this.recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractFileTrackImporter(Context context, ContentProviderUtils contentProviderUtils, long importTrackId) {
|
AbstractFileTrackImporter(Context context, ContentProviderUtils contentProviderUtils, Track.Id importTrackId) {
|
||||||
this(context, contentProviderUtils);
|
this(context, contentProviderUtils);
|
||||||
this.importTrackId = importTrackId;
|
this.importTrackId = importTrackId;
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long importFile(InputStream inputStream) {
|
public Track.Id importFile(InputStream inputStream) {
|
||||||
try {
|
try {
|
||||||
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
|
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
@@ -140,7 +140,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
} catch (MultiTracksImportException | IOException | SAXException | SQLiteConstraintException | ParserConfigurationException e) {
|
} catch (MultiTracksImportException | IOException | SAXException | SQLiteConstraintException | ParserConfigurationException e) {
|
||||||
Log.e(TAG, "Unable to import file", e);
|
Log.e(TAG, "Unable to import file", e);
|
||||||
cleanImport();
|
cleanImport();
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,14 +153,14 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long trackId = trackIds.get(size - 1);
|
Track.Id trackId = trackIds.get(size - 1);
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
if (track == null) {
|
if (track == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int waypointPosition = -1;
|
int waypointPosition = -1;
|
||||||
Waypoint waypoint = null;
|
Marker waypoint = null;
|
||||||
TrackPoint trackPoint = null;
|
TrackPoint trackPoint = null;
|
||||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics().getStartTime_ms());
|
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics().getStartTime_ms());
|
||||||
// TODO Should not be necessary anymore?
|
// TODO Should not be necessary anymore?
|
||||||
@@ -209,8 +209,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
long duration = trackStatisticsUpdater.getTrackStatistics().getTotalTime();
|
long duration = trackStatisticsUpdater.getTrackStatistics().getTotalTime();
|
||||||
|
|
||||||
// Insert waypoint
|
// Insert waypoint
|
||||||
Waypoint newWaypoint = new Waypoint(waypoint.getName(), waypointDescription, waypoint.getCategory(), icon, track.getId(), length, duration, trackPoint.getLocation(), waypoint.getPhotoUrl());
|
Marker newWaypoint = new Marker(waypoint.getName(), waypointDescription, waypoint.getCategory(), icon, track.getId(), length, duration, trackPoint.getLocation(), waypoint.getPhotoUrl());
|
||||||
contentProviderUtils.insertWaypoint(newWaypoint);
|
contentProviderUtils.insertMarker(newWaypoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the next waypoint
|
// Load the next waypoint
|
||||||
@@ -225,10 +225,10 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
*/
|
*/
|
||||||
protected void onTrackStart() throws SAXException {
|
protected void onTrackStart() throws SAXException {
|
||||||
trackData = new TrackData();
|
trackData = new TrackData();
|
||||||
long trackId;
|
Track.Id trackId;
|
||||||
if (importTrackId == -1L) {
|
if (importTrackId == null) {
|
||||||
Uri uri = contentProviderUtils.insertTrack(trackData.track);
|
Uri uri = contentProviderUtils.insertTrack(trackData.track);
|
||||||
trackId = Long.parseLong(uri.getLastPathSegment());
|
trackId = new Track.Id(Long.parseLong(uri.getLastPathSegment()));
|
||||||
} else {
|
} else {
|
||||||
if (trackIds.size() > 0) {
|
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));
|
||||||
@@ -314,7 +314,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
||||||
throw new SAXException(createErrorMessage("Invalid location detected: " + trackPoint));
|
throw new SAXException(createErrorMessage("Invalid location detected: " + trackPoint));
|
||||||
}
|
}
|
||||||
Waypoint waypoint = new Waypoint(trackPoint.getLocation());
|
Marker waypoint = new Marker(trackPoint.getLocation());
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
waypoint.setName(name);
|
waypoint.setName(name);
|
||||||
@@ -399,7 +399,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
* @param externalPhotoUrl the file name
|
* @param externalPhotoUrl the file name
|
||||||
*/
|
*/
|
||||||
protected String getInternalPhotoUrl(String externalPhotoUrl) {
|
protected String getInternalPhotoUrl(String externalPhotoUrl) {
|
||||||
if (importTrackId == -1L) {
|
if (importTrackId == null) {
|
||||||
Log.e(TAG, "Track id is invalid.");
|
Log.e(TAG, "Track id is invalid.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -517,7 +517,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
* Cleans up import.
|
* Cleans up import.
|
||||||
*/
|
*/
|
||||||
private void cleanImport() {
|
private void cleanImport() {
|
||||||
for (long trackId : trackIds) {
|
for (Track.Id trackId : trackIds) {
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ import java.util.List;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.KmzTrackExporter;
|
import de.dennisguse.opentracks.io.file.exporter.KmzTrackExporter;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
@@ -52,7 +53,7 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
private static final int BUFFER_SIZE = 4096;
|
private static final int BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private long importTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
private Track.Id importTrackId; //TODO needed?
|
||||||
private final Uri uriKmzFile;
|
private final Uri uriKmzFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,18 +66,18 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long importFile(InputStream inputStream) {
|
public Track.Id importFile(InputStream inputStream) {
|
||||||
long trackId;
|
Track.Id trackId;
|
||||||
|
|
||||||
if (!copyKmzImages()) {
|
if (!copyKmzImages()) {
|
||||||
cleanImport(context, importTrackId);
|
cleanImport(context, importTrackId);
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
trackId = findAndParseKmlFile(inputStream);
|
trackId = findAndParseKmlFile(inputStream);
|
||||||
if (trackId == -1L) {
|
if (trackId == null) {
|
||||||
cleanImport(context, importTrackId);
|
cleanImport(context, importTrackId);
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOrphanImages(context, trackId);
|
deleteOrphanImages(context, trackId);
|
||||||
@@ -91,7 +92,7 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
*/
|
*/
|
||||||
private boolean copyKmzImages() {
|
private boolean copyKmzImages() {
|
||||||
try (InputStream inputStream = context.getContentResolver().openInputStream(uriKmzFile);
|
try (InputStream inputStream = context.getContentResolver().openInputStream(uriKmzFile);
|
||||||
ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
|
ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
|
||||||
ZipEntry zipEntry;
|
ZipEntry zipEntry;
|
||||||
|
|
||||||
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
||||||
@@ -140,7 +141,7 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
* Returns true if fileName ends with some of the KMZ_IMAGES_EXT suffixes.
|
* Returns true if fileName ends with some of the KMZ_IMAGES_EXT suffixes.
|
||||||
* Otherwise returns false.
|
* Otherwise returns false.
|
||||||
*/
|
*/
|
||||||
private boolean hasImageExtension(String fileName) {
|
private boolean hasImageExtension(String fileName) {
|
||||||
if (fileName == null) {
|
if (fileName == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -155,27 +156,28 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds KmzTrackExporter.KMZ_KML_FILE file inside kmz file (inputStream) and it parses it.
|
* Finds KmzTrackExporter.KMZ_KML_FILE file inside kmz file (inputStream) and it parses it.
|
||||||
|
* TODO: May load multiple tracks, but only returns the last Track.Id.
|
||||||
*
|
*
|
||||||
* @param inputStream kmz input stream.
|
* @param inputStream kmz input stream.
|
||||||
* @return -1 if error or the id of the track otherwise.
|
* @return null if error or the id of the track otherwise.
|
||||||
*/
|
*/
|
||||||
private long findAndParseKmlFile(InputStream inputStream) {
|
private Track.Id findAndParseKmlFile(InputStream inputStream) {
|
||||||
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
|
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
|
||||||
ZipEntry zipEntry;
|
ZipEntry zipEntry;
|
||||||
long trackId = -1L;
|
Track.Id trackId = null;
|
||||||
|
|
||||||
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
||||||
if (Thread.interrupted()) {
|
if (Thread.interrupted()) {
|
||||||
Log.d(TAG, "Thread interrupted");
|
Log.d(TAG, "Thread interrupted");
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String fileName = zipEntry.getName();
|
String fileName = zipEntry.getName();
|
||||||
if (KmzTrackExporter.KMZ_KML_FILE.equals(fileName)) {
|
if (KmzTrackExporter.KMZ_KML_FILE.equals(fileName)) {
|
||||||
trackId = parseKml(zipInputStream);
|
trackId = parseKml(zipInputStream);
|
||||||
if (trackId == -1L) {
|
if (trackId != null) {
|
||||||
Log.d(TAG, "Unable to parse kml in kmz");
|
Log.d(TAG, "Unable to parse kml in kmz");
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +186,7 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
return trackId;
|
return trackId;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Unable to import file", e);
|
Log.e(TAG, "Unable to import file", e);
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,13 +196,13 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
* @param context the Context object.
|
* @param context the Context object.
|
||||||
* @param trackId the id of the Track.
|
* @param trackId the id of the Track.
|
||||||
*/
|
*/
|
||||||
private void deleteOrphanImages(Context context, long trackId) {
|
private void deleteOrphanImages(Context context, Track.Id trackId) {
|
||||||
if (trackId != 1L) {
|
if (!trackId.isValid()) {
|
||||||
// 1.- Gets all photo names in the waypoints of the track identified by id.
|
// 1.- Gets all photo names in the waypoints of the track identified by id.
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||||
List<Waypoint> waypoints = contentProviderUtils.getWaypoints(trackId);
|
List<Marker> waypoints = contentProviderUtils.getMarkers(trackId);
|
||||||
List<String> photosName = new ArrayList<>();
|
List<String> photosName = new ArrayList<>();
|
||||||
for (Waypoint w : waypoints) {
|
for (Marker w : waypoints) {
|
||||||
if (w.hasPhoto()) {
|
if (w.hasPhoto()) {
|
||||||
String photoUrl = Uri.decode(w.getPhotoUrl());
|
String photoUrl = Uri.decode(w.getPhotoUrl());
|
||||||
photosName.add(photoUrl.substring(photoUrl.lastIndexOf(File.separatorChar) + 1));
|
photosName.add(photoUrl.substring(photoUrl.lastIndexOf(File.separatorChar) + 1));
|
||||||
@@ -227,7 +229,7 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
*
|
*
|
||||||
* @param trackId the trackId
|
* @param trackId the trackId
|
||||||
*/
|
*/
|
||||||
private void cleanImport(Context context, long trackId) {
|
private void cleanImport(Context context, Track.Id trackId) {
|
||||||
if (PreferencesUtils.isRecording(trackId)) {
|
if (PreferencesUtils.isRecording(trackId)) {
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
@@ -240,7 +242,7 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
* @param zipInputStream the zip input stream
|
* @param zipInputStream the zip input stream
|
||||||
* @return the imported track id or -1L
|
* @return the imported track id or -1L
|
||||||
*/
|
*/
|
||||||
private long parseKml(ZipInputStream zipInputStream) throws IOException {
|
private Track.Id parseKml(ZipInputStream zipInputStream) throws IOException {
|
||||||
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context);
|
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context);
|
||||||
|
|
||||||
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getKml(zipInputStream))) {
|
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getKml(zipInputStream))) {
|
||||||
@@ -271,7 +273,7 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
* @param fileName the file name
|
* @param fileName the file name
|
||||||
*/
|
*/
|
||||||
private void readAndSaveImageFile(ZipInputStream zipInputStream, String fileName) throws IOException {
|
private void readAndSaveImageFile(ZipInputStream zipInputStream, String fileName) throws IOException {
|
||||||
if (importTrackId == -1L || fileName.equals("")) {
|
if (importTrackId == null || fileName.equals("")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ package de.dennisguse.opentracks.io.file.importer;
|
|||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for a track importer.
|
* Interface for a track importer.
|
||||||
*
|
*
|
||||||
@@ -28,8 +30,8 @@ public interface TrackImporter {
|
|||||||
* Import a file.
|
* Import a file.
|
||||||
*
|
*
|
||||||
* @param inputStream the file's input stream
|
* @param inputStream the file's input stream
|
||||||
* @return the imported track id or RECORDING_TRACK_ID_DEFAULT.
|
* @return the imported track id or null.
|
||||||
*/
|
*/
|
||||||
//TODO Figure out how can make the import an atomic operation (incl. database transaction rollback).
|
//TODO Figure out how can make the import an atomic operation (incl. database transaction rollback).
|
||||||
long importFile(InputStream inputStream);
|
Track.Id importFile(InputStream inputStream);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ import java.util.List;
|
|||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.TrackListActivity;
|
import de.dennisguse.opentracks.TrackListActivity;
|
||||||
import de.dennisguse.opentracks.TrackRecordingActivity;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
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.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||||
@@ -76,7 +76,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
private PeriodicTaskExecutor voiceExecutor;
|
private PeriodicTaskExecutor voiceExecutor;
|
||||||
private TrackRecordingServiceNotificationManager notificationManager;
|
private TrackRecordingServiceNotificationManager notificationManager;
|
||||||
|
|
||||||
private long recordingTrackId;
|
private Track.Id recordingTrackId;
|
||||||
private boolean recordingTrackPaused;
|
private boolean recordingTrackPaused;
|
||||||
private int recordingDistanceInterval;
|
private int recordingDistanceInterval;
|
||||||
private int maxRecordingDistance;
|
private int maxRecordingDistance;
|
||||||
@@ -138,7 +138,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
notificationManager = new TrackRecordingServiceNotificationManager(this);
|
notificationManager = new TrackRecordingServiceNotificationManager(this);
|
||||||
|
|
||||||
// onSharedPreferenceChanged might not set recordingTrackId.
|
// onSharedPreferenceChanged might not set recordingTrackId.
|
||||||
recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
recordingTrackId = null;
|
||||||
|
|
||||||
PreferencesUtils.register(this, sharedPreferenceChangeListener);
|
PreferencesUtils.register(this, sharedPreferenceChangeListener);
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
||||||
@@ -204,7 +204,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
return recordingTrackPaused;
|
return recordingTrackPaused;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRecordingTrackId() {
|
public Track.Id getRecordingTrackId() {
|
||||||
return recordingTrackId;
|
return recordingTrackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +215,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
return trackStatisticsUpdater.getTrackStatistics();
|
return trackStatisticsUpdater.getTrackStatistics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Throw exception, when not recording.
|
||||||
public long getTotalTime() {
|
public long getTotalTime() {
|
||||||
if (trackStatisticsUpdater == null) {
|
if (trackStatisticsUpdater == null) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -225,28 +226,23 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
return trackStatisticsUpdater.getTrackStatistics().getTotalTime();
|
return trackStatisticsUpdater.getTrackStatistics().getTotalTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Marker.Id insertMarker(String name, String category, String description, String photoUrl) {
|
||||||
* Inserts a waypoint.
|
|
||||||
*
|
|
||||||
* @return the waypoint id
|
|
||||||
*/
|
|
||||||
public long insertWaypoint(String name, String category, String description, String photoUrl) {
|
|
||||||
if (!isRecording() || isPaused()) {
|
if (!isRecording() || isPaused()) {
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
int nextWaypointNumber = contentProviderUtils.getNextWaypointNumber(recordingTrackId);
|
int nextMarkerNumber = contentProviderUtils.getNextMarkerNumber(recordingTrackId);
|
||||||
if (nextWaypointNumber == -1) {
|
if (nextMarkerNumber == -1) {
|
||||||
nextWaypointNumber = 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);
|
TrackPoint trackPoint = getLastValidTrackPointInCurrentSegment(recordingTrackId);
|
||||||
if (trackPoint == null) {
|
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 -1L;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
category = category != null ? category : "";
|
category = category != null ? category : "";
|
||||||
@@ -258,10 +254,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
double length = stats.getTotalDistance();
|
double length = stats.getTotalDistance();
|
||||||
long duration = stats.getTotalTime();
|
long duration = stats.getTotalTime();
|
||||||
|
|
||||||
// Insert waypoint
|
// Insert marker
|
||||||
Waypoint waypoint = new Waypoint(name, description, category, icon, recordingTrackId, length, duration, trackPoint.getLocation(), photoUrl);
|
Marker marker = new Marker(name, description, category, icon, recordingTrackId, length, duration, trackPoint.getLocation(), photoUrl);
|
||||||
Uri uri = contentProviderUtils.insertWaypoint(waypoint);
|
Uri uri = contentProviderUtils.insertMarker(marker);
|
||||||
return ContentUris.parseId(uri);
|
return new Marker.Id(ContentUris.parseId(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -269,10 +265,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
*
|
*
|
||||||
* @return the track id
|
* @return the track id
|
||||||
*/
|
*/
|
||||||
long startNewTrack() {
|
Track.Id startNewTrack() {
|
||||||
if (isRecording()) {
|
if (isRecording()) {
|
||||||
Log.d(TAG, "Ignore startNewTrack. Already recording.");
|
Log.d(TAG, "Ignore startNewTrack. Already recording.");
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
trackStatisticsUpdater = new TrackStatisticsUpdater(now);
|
trackStatisticsUpdater = new TrackStatisticsUpdater(now);
|
||||||
@@ -280,7 +276,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
// Insert a track
|
// Insert a track
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
Uri uri = contentProviderUtils.insertTrack(track);
|
Uri uri = contentProviderUtils.insertTrack(track);
|
||||||
long trackId = ContentUris.parseId(uri);
|
Track.Id trackId = new Track.Id(ContentUris.parseId(uri));
|
||||||
|
|
||||||
// Update shared preferences
|
// Update shared preferences
|
||||||
updateRecordingState(trackId, false);
|
updateRecordingState(trackId, false);
|
||||||
@@ -305,7 +301,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
*
|
*
|
||||||
* @param trackId the id of the track to be resumed.
|
* @param trackId the id of the track to be resumed.
|
||||||
*/
|
*/
|
||||||
void resumeTrack(long trackId) {
|
void resumeTrack(Track.Id trackId) {
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
if (track == null) {
|
if (track == null) {
|
||||||
Log.e(TAG, "Ignore resumeTrack. Track " + trackId + " does not exists.");
|
Log.e(TAG, "Ignore resumeTrack. Track " + trackId + " does not exists.");
|
||||||
@@ -333,7 +329,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
if (track == null) {
|
if (track == null) {
|
||||||
if (isRecording()) {
|
if (isRecording()) {
|
||||||
Log.w(TAG, "track is null, but recordingTrackId not -1L. " + recordingTrackId);
|
Log.w(TAG, "track is null, but recordingTrackId not -1L. " + recordingTrackId);
|
||||||
updateRecordingState(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, true);
|
updateRecordingState(null, true);
|
||||||
}
|
}
|
||||||
showNotification(false);
|
showNotification(false);
|
||||||
return;
|
return;
|
||||||
@@ -403,10 +399,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Need to remember the recordingTrackId before setting it to -1L
|
// Need to remember the recordingTrackId before setting it to -1L
|
||||||
long trackId = recordingTrackId;
|
Track.Id trackId = recordingTrackId;
|
||||||
boolean wasPaused = recordingTrackPaused;
|
boolean wasPaused = recordingTrackPaused;
|
||||||
|
|
||||||
updateRecordingState(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, true);
|
updateRecordingState(null, true);
|
||||||
|
|
||||||
// Update database
|
// Update database
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
@@ -489,7 +485,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
* @return the location or null
|
* @return the location or null
|
||||||
*/
|
*/
|
||||||
private TrackPoint getLastValidTrackPointInCurrentSegment(long trackId) {
|
private TrackPoint getLastValidTrackPointInCurrentSegment(Track.Id trackId) {
|
||||||
if (!currentSegmentHasTrackPoint()) {
|
if (!currentSegmentHasTrackPoint()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -507,9 +503,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
* @param trackId the recording track id
|
* @param trackId the recording track id
|
||||||
* @param paused true if the recording is paused
|
* @param paused true if the recording is paused
|
||||||
*/
|
*/
|
||||||
private void updateRecordingState(long trackId, boolean paused) {
|
private void updateRecordingState(Track.Id trackId, boolean paused) {
|
||||||
recordingTrackId = trackId;
|
recordingTrackId = trackId;
|
||||||
PreferencesUtils.setLong(this, R.string.recording_track_id_key, trackId);
|
long currentTrackId = trackId != null ? trackId.getId() : PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
|
PreferencesUtils.setLong(this, R.string.recording_track_id_key, currentTrackId);
|
||||||
recordingTrackPaused = paused;
|
recordingTrackPaused = paused;
|
||||||
PreferencesUtils.setBoolean(this, R.string.recording_track_paused_key, recordingTrackPaused);
|
PreferencesUtils.setBoolean(this, R.string.recording_track_paused_key, recordingTrackPaused);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package de.dennisguse.opentracks.services;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
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.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||||
@@ -43,12 +45,12 @@ class TrackRecordingServiceBinder extends android.os.Binder implements TrackReco
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long startNewTrack() {
|
public Track.Id startNewTrack() {
|
||||||
return trackRecordingService.startNewTrack();
|
return trackRecordingService.startNewTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resumeTrack(long trackId) {
|
public void resumeTrack(Track.Id trackId) {
|
||||||
trackRecordingService.resumeTrack(trackId);
|
trackRecordingService.resumeTrack(trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +80,7 @@ class TrackRecordingServiceBinder extends android.os.Binder implements TrackReco
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRecordingTrackId() {
|
public Track.Id getRecordingTrackId() {
|
||||||
return trackRecordingService.getRecordingTrackId();
|
return trackRecordingService.getRecordingTrackId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,8 +90,8 @@ class TrackRecordingServiceBinder extends android.os.Binder implements TrackReco
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long insertWaypoint(String name, String category, String description, String photoUrl) {
|
public Marker.Id insertMarker(String name, String category, String description, String photoUrl) {
|
||||||
return trackRecordingService.insertWaypoint(name, category, description, photoUrl);
|
return trackRecordingService.insertMarker(name, category, description, photoUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+9
-13
@@ -31,6 +31,8 @@ import androidx.annotation.NonNull;
|
|||||||
import de.dennisguse.opentracks.BuildConfig;
|
import de.dennisguse.opentracks.BuildConfig;
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.TrackEditActivity;
|
import de.dennisguse.opentracks.TrackEditActivity;
|
||||||
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.util.IntentUtils;
|
import de.dennisguse.opentracks.util.IntentUtils;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
|
|
||||||
@@ -177,18 +179,18 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
|
|||||||
/**
|
/**
|
||||||
* Adds a marker.
|
* Adds a marker.
|
||||||
*
|
*
|
||||||
* @return the id of the marker or -1L if none could be created.
|
* @return the id of the marker or null if none could be created.
|
||||||
*/
|
*/
|
||||||
public long 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();
|
TrackRecordingServiceInterface trackRecordingService = getServiceIfBound();
|
||||||
if (trackRecordingService == null) {
|
if (trackRecordingService == null) {
|
||||||
Log.d(TAG, "Unable to add marker, no track recording service");
|
Log.d(TAG, "Unable to add marker, no track recording service");
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
long markerId = trackRecordingService.insertWaypoint(name, category, description, photoUrl);
|
Marker.Id marker = trackRecordingService.insertMarker(name, category, description, photoUrl);
|
||||||
if (markerId != -1L) {
|
if (marker != null) {
|
||||||
Toast.makeText(context, R.string.marker_add_success, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.marker_add_success, Toast.LENGTH_SHORT).show();
|
||||||
return markerId;
|
return marker;
|
||||||
}
|
}
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
Log.e(TAG, "Unable to add marker.", e);
|
Log.e(TAG, "Unable to add marker.", e);
|
||||||
@@ -196,15 +198,9 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
|
|||||||
}
|
}
|
||||||
|
|
||||||
Toast.makeText(context, R.string.marker_add_error, Toast.LENGTH_LONG).show();
|
Toast.makeText(context, R.string.marker_add_error, Toast.LENGTH_LONG).show();
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the recording.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param showEditor true to show the editor
|
|
||||||
*/
|
|
||||||
public void stopRecording(@NonNull Context context, boolean showEditor) {
|
public void stopRecording(@NonNull Context context, boolean showEditor) {
|
||||||
TrackRecordingServiceInterface trackRecordingService = getServiceIfBound();
|
TrackRecordingServiceInterface trackRecordingService = getServiceIfBound();
|
||||||
if (trackRecordingService == null) {
|
if (trackRecordingService == null) {
|
||||||
@@ -213,7 +209,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
|
|||||||
try {
|
try {
|
||||||
if (showEditor) {
|
if (showEditor) {
|
||||||
// Need to remember the recordingTrackId before calling endCurrentTrack() as endCurrentTrack() sets the value to -1L.
|
// Need to remember the recordingTrackId before calling endCurrentTrack() as endCurrentTrack() sets the value to -1L.
|
||||||
long recordingTrackId = PreferencesUtils.getRecordingTrackId(context);
|
Track.Id recordingTrackId = PreferencesUtils.getRecordingTrackId(context);
|
||||||
trackRecordingService.endCurrentTrack();
|
trackRecordingService.endCurrentTrack();
|
||||||
if (PreferencesUtils.isRecording(context)) {
|
if (PreferencesUtils.isRecording(context)) {
|
||||||
Intent intent = IntentUtils.newIntent(context, TrackEditActivity.class)
|
Intent intent = IntentUtils.newIntent(context, TrackEditActivity.class)
|
||||||
|
|||||||
+9
-37
@@ -17,6 +17,8 @@ package de.dennisguse.opentracks.services;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
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.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||||
@@ -28,46 +30,20 @@ import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
|||||||
*/
|
*/
|
||||||
public interface TrackRecordingServiceInterface {
|
public interface TrackRecordingServiceInterface {
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts gps.
|
|
||||||
*/
|
|
||||||
void startGps();
|
void startGps();
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops gps.
|
|
||||||
*/
|
|
||||||
void stopGps();
|
void stopGps();
|
||||||
|
|
||||||
/**
|
Track.Id startNewTrack();
|
||||||
* Starts recording a new track.
|
|
||||||
*
|
|
||||||
* @return the track ID of the new track.
|
|
||||||
*/
|
|
||||||
long startNewTrack();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resumes the track identified by trackId.
|
|
||||||
*/
|
|
||||||
void resumeTrack(long trackId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pauses the current recording track.
|
|
||||||
*/
|
|
||||||
void pauseCurrentTrack();
|
void pauseCurrentTrack();
|
||||||
|
|
||||||
/**
|
|
||||||
* Resumes the current recording track.
|
|
||||||
*/
|
|
||||||
void resumeCurrentTrack();
|
void resumeCurrentTrack();
|
||||||
|
|
||||||
/**
|
void resumeTrack(Track.Id trackId);
|
||||||
* Ends the current recording track.
|
|
||||||
*/
|
|
||||||
void endCurrentTrack();
|
void endCurrentTrack();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if currently recording a track.
|
|
||||||
*/
|
|
||||||
boolean isRecording();
|
boolean isRecording();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,21 +52,17 @@ public interface TrackRecordingServiceInterface {
|
|||||||
boolean isPaused();
|
boolean isPaused();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current recording track ID. Returns -1 if not recording.
|
* Gets the current recording track ID. Returns null if not recording.
|
||||||
*/
|
*/
|
||||||
long getRecordingTrackId();
|
Track.Id getRecordingTrackId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the total time for the current recording track. Returns 0 if not recording.
|
* Gets the total time for the current recording track. Returns 0 if not recording.
|
||||||
*/
|
*/
|
||||||
|
//TODO milliseconds?
|
||||||
long getTotalTime();
|
long getTotalTime();
|
||||||
|
|
||||||
/**
|
Marker.Id insertMarker(String name, String category, String description, String photoUrl);
|
||||||
* Inserts a waypoint in the current recording track.
|
|
||||||
*
|
|
||||||
* @return the ID of the inserted waypoint
|
|
||||||
*/
|
|
||||||
long insertWaypoint(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. Returns null if there is no data.
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ class GpsStatus {
|
|||||||
// The last valid (not null) location. Null value means that there have not been any location yet.
|
// The last valid (not null) location. Null value means that there have not been any location yet.
|
||||||
private Location lastValidLocation = null;
|
private Location lastValidLocation = null;
|
||||||
|
|
||||||
|
// Flag to prevent GpsStatus checks two or more locations at the same time.
|
||||||
|
private boolean checking = false;
|
||||||
|
|
||||||
private class GpsStatusRunner implements Runnable {
|
private class GpsStatusRunner implements Runnable {
|
||||||
private boolean stopped = false;
|
private boolean stopped = false;
|
||||||
|
|
||||||
@@ -99,16 +102,24 @@ class GpsStatus {
|
|||||||
* It look for GPS changes in lastLocation if it's not null. If it's null then look for in lastValidLocation if any.
|
* It look for GPS changes in lastLocation if it's not null. If it's null then look for in lastValidLocation if any.
|
||||||
*/
|
*/
|
||||||
public void onLocationChanged(final Location location) {
|
public void onLocationChanged(final Location location) {
|
||||||
|
if (checking == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checking = true;
|
||||||
if (lastLocation != null) {
|
if (lastLocation != null) {
|
||||||
checkStatusFromLastLocation();
|
checkStatusFromLastLocation();
|
||||||
} else if (lastValidLocation != null) {
|
} else if (lastValidLocation != null) {
|
||||||
checkStatusFromLastValidLocation();
|
checkStatusFromLastValidLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
lastLocation = location;
|
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
|
// Update location's time to the current time millis when location has been received.
|
||||||
|
location.setTime(System.currentTimeMillis());
|
||||||
lastValidLocation = location;
|
lastValidLocation = location;
|
||||||
}
|
}
|
||||||
|
lastLocation = location;
|
||||||
|
checking = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,7 +130,7 @@ class GpsStatus {
|
|||||||
*/
|
*/
|
||||||
private void checkStatusFromLastLocation() {
|
private void checkStatusFromLastLocation() {
|
||||||
if (System.currentTimeMillis() - lastLocation.getTime() > signalLostThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_LOST) {
|
if (System.currentTimeMillis() - lastLocation.getTime() > signalLostThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_LOST) {
|
||||||
// So much time without receiving signal -> signal lost.
|
// Too much time without receiving signal -> signal lost.
|
||||||
GpsStatusValue oldStatus = gpsStatus;
|
GpsStatusValue oldStatus = gpsStatus;
|
||||||
gpsStatus = GpsStatusValue.GPS_SIGNAL_LOST;
|
gpsStatus = GpsStatusValue.GPS_SIGNAL_LOST;
|
||||||
sendStatus(oldStatus, gpsStatus);
|
sendStatus(oldStatus, gpsStatus);
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop(Context context) {
|
public void onStop(Context context) {
|
||||||
locationManager = null;
|
|
||||||
unregisterLocationListener();
|
unregisterLocationListener();
|
||||||
|
locationManager = null;
|
||||||
if (gpsStatus != null) {
|
if (gpsStatus != null) {
|
||||||
gpsStatus.stop();
|
gpsStatus.stop();
|
||||||
gpsStatus = null;
|
gpsStatus = null;
|
||||||
|
|||||||
+13
-1
@@ -22,14 +22,18 @@ import android.speech.tts.TextToSpeech;
|
|||||||
import android.speech.tts.UtteranceProgressListener;
|
import android.speech.tts.UtteranceProgressListener;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.AnnouncementUtils;
|
import de.dennisguse.opentracks.util.AnnouncementUtils;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
|
import de.dennisguse.opentracks.util.UnitConversions;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class will periodically announce the user's {@link TrackStatistics}.
|
* This class will periodically announce the user's {@link TrackStatistics}.
|
||||||
@@ -159,9 +163,17 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
Log.i(TAG, "Speech is not allowed at this time.");
|
Log.i(TAG, "Speech is not allowed at this time.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Track track = contentProviderUtils.getTrack(PreferencesUtils.getRecordingTrackId(context));
|
Track track = contentProviderUtils.getTrack(PreferencesUtils.getRecordingTrackId(context));
|
||||||
String category = track != null ? track.getCategory() : "";
|
String category = track != null ? track.getCategory() : "";
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, trackStatistics, category);
|
|
||||||
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(track.getId());
|
||||||
|
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||||
|
intervalStatistics.build(trackPoints, (float) (PreferencesUtils.isMetricUnits(context) ? 1 * UnitConversions.KM_TO_M : 1 * UnitConversions.MI_TO_M));
|
||||||
|
int numIntervals = intervalStatistics.getIntervalList().size();
|
||||||
|
IntervalStatistics.Interval lastInterval = numIntervals > 0 ? intervalStatistics.getIntervalList().get(numIntervals - 1) : null;
|
||||||
|
|
||||||
|
String announcement = AnnouncementUtils.getAnnouncement(context, trackStatistics, category, lastInterval);
|
||||||
speakAnnouncement(announcement);
|
speakAnnouncement(announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-1
@@ -8,6 +8,8 @@ import android.bluetooth.le.ScanResult;
|
|||||||
import android.bluetooth.le.ScanSettings;
|
import android.bluetooth.le.ScanSettings;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.graphics.drawable.Animatable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.ParcelUuid;
|
import android.os.ParcelUuid;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -16,6 +18,7 @@ import android.util.Log;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.preference.DialogPreference;
|
import androidx.preference.DialogPreference;
|
||||||
import androidx.preference.PreferenceDialogFragmentCompat;
|
import androidx.preference.PreferenceDialogFragmentCompat;
|
||||||
|
|
||||||
@@ -189,7 +192,11 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
|
|||||||
BluetoothLeSensorPreferenceDialog.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
|
BluetoothLeSensorPreferenceDialog.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
});
|
});
|
||||||
builder.setIcon(R.drawable.ic_bluetooth_searching_24dp);
|
|
||||||
|
Drawable icon = ContextCompat.getDrawable(getContext(), R.drawable.ic_bluetooth_searching_animated_24dp);
|
||||||
|
((Animatable) icon).start();
|
||||||
|
builder.setIcon(icon);
|
||||||
|
|
||||||
builder.setPositiveButton(null, null);
|
builder.setPositiveButton(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,18 +2,22 @@ package de.dennisguse.opentracks.util;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||||
|
|
||||||
public class AnnouncementUtils {
|
public class AnnouncementUtils {
|
||||||
|
|
||||||
private AnnouncementUtils() {}
|
private AnnouncementUtils() {}
|
||||||
|
|
||||||
public static String getAnnouncement(Context context, TrackStatistics trackStatistics, String category) {
|
public static String getAnnouncement(Context context, TrackStatistics trackStatistics, String category, @Nullable IntervalStatistics.Interval currentInterval) {
|
||||||
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
|
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
|
||||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(context, category);
|
boolean reportSpeed = PreferencesUtils.isReportSpeed(context, category);
|
||||||
double distance = trackStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
double distance = trackStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
||||||
double distancePerTime = trackStatistics.getAverageMovingSpeed() * UnitConversions.MPS_TO_KMH;
|
double distancePerTime = trackStatistics.getAverageMovingSpeed() * UnitConversions.MPS_TO_KMH;
|
||||||
|
double currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed_ms() * UnitConversions.MPS_TO_KMH : 0;
|
||||||
|
|
||||||
if (distance == 0) {
|
if (distance == 0) {
|
||||||
return context.getString(R.string.voice_total_distance_zero);
|
return context.getString(R.string.voice_total_distance_zero);
|
||||||
@@ -22,23 +26,36 @@ public class AnnouncementUtils {
|
|||||||
if (!metricUnits) {
|
if (!metricUnits) {
|
||||||
distance *= UnitConversions.KM_TO_MI;
|
distance *= UnitConversions.KM_TO_MI;
|
||||||
distancePerTime *= UnitConversions.KM_TO_MI;
|
distancePerTime *= UnitConversions.KM_TO_MI;
|
||||||
|
currentDistancePerTime *= UnitConversions.KM_TO_MI;
|
||||||
}
|
}
|
||||||
|
|
||||||
String rate;
|
String rate;
|
||||||
|
String currentRate;
|
||||||
|
String currentRateMsg = "";
|
||||||
if (reportSpeed) {
|
if (reportSpeed) {
|
||||||
int speedId = metricUnits ? R.plurals.voiceSpeedKilometersPerHour : R.plurals.voiceSpeedMilesPerHour;
|
int speedId = metricUnits ? R.plurals.voiceSpeedKilometersPerHour : R.plurals.voiceSpeedMilesPerHour;
|
||||||
rate = context.getResources().getQuantityString(speedId, getQuantityCount(distancePerTime), distancePerTime);
|
rate = context.getResources().getQuantityString(speedId, getQuantityCount(distancePerTime), distancePerTime);
|
||||||
|
|
||||||
|
currentRate = context.getResources().getQuantityString(speedId, getQuantityCount(currentDistancePerTime), currentDistancePerTime);
|
||||||
|
currentRateMsg = metricUnits ? context.getString(R.string.voice_speed_current_kilometer, currentRate) : context.getString(R.string.voice_speed_current_mile, currentRate);
|
||||||
} else {
|
} else {
|
||||||
double timePerDistance = distancePerTime == 0 ? 0.0 : 1 / distancePerTime;
|
double timePerDistance = distancePerTime == 0 ? 0.0 : 1 / distancePerTime;
|
||||||
int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile;
|
int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile;
|
||||||
long time = Math.round(timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
|
long time = Math.round(timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
|
||||||
rate = context.getString(paceId, getAnnounceTime(context, time));
|
rate = context.getString(paceId, getAnnounceTime(context, time));
|
||||||
|
|
||||||
|
double currentTimePerDistance = currentDistancePerTime == 0 ? 0.0 : 1 / currentDistancePerTime;
|
||||||
|
long currentTime = Math.round(currentTimePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
|
||||||
|
currentRate = context.getString(paceId, getAnnounceTime(context, currentTime));
|
||||||
|
currentRateMsg = metricUnits ? context.getString(R.string.voice_pace_current_kilometer, currentRate) : context.getString(R.string.voice_pace_current_mile, currentRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
int totalDistanceId = metricUnits ? R.plurals.voiceTotalDistanceKilometers : R.plurals.voiceTotalDistanceMiles;
|
int totalDistanceId = metricUnits ? R.plurals.voiceTotalDistanceKilometers : R.plurals.voiceTotalDistanceMiles;
|
||||||
String totalDistance = context.getResources().getQuantityString(totalDistanceId, getQuantityCount(distance), distance);
|
String totalDistance = context.getResources().getQuantityString(totalDistanceId, getQuantityCount(distance), distance);
|
||||||
|
|
||||||
return context.getString(R.string.voice_template, totalDistance, getAnnounceTime(context, trackStatistics.getMovingTime()), rate);
|
currentRateMsg = currentInterval == null ? "" : " " + currentRateMsg;
|
||||||
|
|
||||||
|
return context.getString(R.string.voice_template, totalDistance, getAnnounceTime(context, trackStatistics.getMovingTime()), rate) + currentRateMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getAnnounceTime(Context context, long time) {
|
private static String getAnnounceTime(Context context, long time) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.BuildConfig;
|
import de.dennisguse.opentracks.BuildConfig;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for dealing with files.
|
* Utilities for dealing with files.
|
||||||
@@ -63,8 +64,8 @@ public class FileUtils {
|
|||||||
return context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
return context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getPhotoDir(Context context, long trackId) {
|
public static File getPhotoDir(Context context, Track.Id trackId) {
|
||||||
File photoDirectory = new File(getPhotoDir(context), "" + trackId);
|
File photoDirectory = new File(getPhotoDir(context), "" + trackId.getId());
|
||||||
photoDirectory.mkdirs();
|
photoDirectory.mkdirs();
|
||||||
return photoDirectory;
|
return photoDirectory;
|
||||||
}
|
}
|
||||||
@@ -223,7 +224,7 @@ public class FileUtils {
|
|||||||
* @param context the context.
|
* @param context the context.
|
||||||
* @param trackId the track id.
|
* @param trackId the track id.
|
||||||
*/
|
*/
|
||||||
public static String getImageUrl(Context context, long trackId) {
|
public static String getImageUrl(Context context, Track.Id trackId) {
|
||||||
File dir = FileUtils.getPhotoDir(context, trackId);
|
File dir = FileUtils.getPhotoDir(context, trackId);
|
||||||
|
|
||||||
String fileName = SimpleDateFormat.getDateTimeInstance().format(new Date());
|
String fileName = SimpleDateFormat.getDateTimeInstance().format(new Date());
|
||||||
@@ -267,7 +268,7 @@ public class FileUtils {
|
|||||||
* @param uri the uri to check.
|
* @param uri the uri to check.
|
||||||
* @return File object or null.
|
* @return File object or null.
|
||||||
*/
|
*/
|
||||||
public static File getPhotoFileIfExists(Context context, long trackId, Uri uri) {
|
public static File getPhotoFileIfExists(Context context, Track.Id trackId, Uri uri) {
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
Log.w(TAG, "URI object is null.");
|
Log.w(TAG, "URI object is null.");
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ import android.net.Uri;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
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.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +45,7 @@ public class IntentDashboardUtils {
|
|||||||
* @param context the context
|
* @param context the context
|
||||||
* @param trackIds the track ids
|
* @param trackIds the track ids
|
||||||
*/
|
*/
|
||||||
public static void startDashboard(Context context, long[] trackIds, boolean isRecording) {
|
public static void startDashboard(Context context, boolean isRecording, Track.Id... trackIds) {
|
||||||
if (trackIds.length == 0) {
|
if (trackIds.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -52,7 +55,7 @@ public class IntentDashboardUtils {
|
|||||||
ArrayList<Uri> uris = new ArrayList<>();
|
ArrayList<Uri> uris = new ArrayList<>();
|
||||||
uris.add(TRACK_URI_INDEX, Uri.withAppendedPath(TracksColumns.CONTENT_URI, trackIdList));
|
uris.add(TRACK_URI_INDEX, Uri.withAppendedPath(TracksColumns.CONTENT_URI, trackIdList));
|
||||||
uris.add(TRACKPOINTS_URI_INDEX, Uri.withAppendedPath(TrackPointsColumns.CONTENT_URI_BY_TRACKID, trackIdList));
|
uris.add(TRACKPOINTS_URI_INDEX, Uri.withAppendedPath(TrackPointsColumns.CONTENT_URI_BY_TRACKID, trackIdList));
|
||||||
uris.add(WAYPOINTS_URI_INDEX, Uri.withAppendedPath(WaypointsColumns.CONTENT_URI_BY_TRACKID, trackIdList));
|
uris.add(WAYPOINTS_URI_INDEX, Uri.withAppendedPath(MarkerColumns.CONTENT_URI_BY_TRACKID, trackIdList));
|
||||||
|
|
||||||
Intent intent = new Intent(ACTION_DASHBOARD);
|
Intent intent = new Intent(ACTION_DASHBOARD);
|
||||||
intent.putParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD, uris);
|
intent.putParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD, uris);
|
||||||
@@ -73,14 +76,14 @@ public class IntentDashboardUtils {
|
|||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long[] extractTrackIdsFromIntent(@NonNull Intent intent) {
|
public static Set<Track.Id> extractTrackIdsFromIntent(@NonNull Intent intent) {
|
||||||
final ArrayList<Uri> uris = intent.getParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD);
|
final ArrayList<Uri> uris = intent.getParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD);
|
||||||
final Uri tracksUri = uris.get(TRACK_URI_INDEX);
|
final Uri tracksUri = uris.get(TRACK_URI_INDEX);
|
||||||
|
|
||||||
String[] trackIdsString = ContentProviderUtils.parseTrackIdsFromUri(tracksUri);
|
String[] trackIdsString = ContentProviderUtils.parseTrackIdsFromUri(tracksUri);
|
||||||
long[] trackIds = new long[trackIdsString.length];
|
Set<Track.Id> trackIds = new HashSet<>(trackIdsString.length);
|
||||||
for (int i = 0; i < trackIdsString.length; i++) {
|
for (String s : trackIdsString) {
|
||||||
trackIds[i] = Long.parseLong(trackIdsString[i]);
|
trackIds.add(new Track.Id(Long.parseLong(s)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return trackIds;
|
return trackIds;
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ import java.util.Date;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.DescriptionGenerator;
|
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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.ShareContentProvider;
|
import de.dennisguse.opentracks.content.provider.ShareContentProvider;
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ public class IntentUtils {
|
|||||||
* @param context the context
|
* @param context the context
|
||||||
* @param trackIds the track ids
|
* @param trackIds the track ids
|
||||||
*/
|
*/
|
||||||
public static Intent newShareFileIntent(Context context, long[] trackIds) {
|
public static Intent newShareFileIntent(Context context, Track.Id... trackIds) {
|
||||||
if (trackIds.length == 0) {
|
if (trackIds.length == 0) {
|
||||||
throw new RuntimeException("Need to share at least one track.");
|
throw new RuntimeException("Need to share at least one track.");
|
||||||
}
|
}
|
||||||
@@ -84,14 +84,14 @@ public class IntentUtils {
|
|||||||
String mime = "";
|
String mime = "";
|
||||||
|
|
||||||
ArrayList<Uri> uris = new ArrayList<>();
|
ArrayList<Uri> uris = new ArrayList<>();
|
||||||
for (long trackId : trackIds) {
|
for (Track.Id trackId : trackIds) {
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
if (track == null) {
|
if (track == null) {
|
||||||
Log.e(TAG, "TrackId " + trackId + " could not be resolved.");
|
Log.e(TAG, "TrackId " + trackId + " could not be resolved.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(new long[]{trackId}, track.getName(), PreferencesUtils.getExportTrackFileFormat(context));
|
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackId, track.getName(), PreferencesUtils.getExportTrackFileFormat(context));
|
||||||
uris.add(uriAndMime.first);
|
uris.add(uriAndMime.first);
|
||||||
mime = uriAndMime.second;
|
mime = uriAndMime.second;
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ public class IntentUtils {
|
|||||||
.putExtra(Intent.EXTRA_TEXT, context.getString(R.string.share_image_body));
|
.putExtra(Intent.EXTRA_TEXT, context.getString(R.string.share_image_body));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showCoordinateOnMap(Context context, Waypoint waypoint) {
|
public static void showCoordinateOnMap(Context context, Marker waypoint) {
|
||||||
showCoordinateOnMap(context, waypoint.getLocation().getLatitude(), waypoint.getLocation().getLongitude(), waypoint.getName());
|
showCoordinateOnMap(context, waypoint.getLocation().getLatitude(), waypoint.getLocation().getLongitude(), waypoint.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +154,6 @@ public class IntentUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a take picture request to the camera app.
|
* Sends a take picture request to the camera app.
|
||||||
* The picture is then stored in the track's folder.
|
* The picture is then stored in the track's folder.
|
||||||
@@ -162,7 +161,7 @@ public class IntentUtils {
|
|||||||
* @param context the context
|
* @param context the context
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
public static Pair<Intent, Uri> createTakePictureIntent(Context context, long trackId) {
|
public static Pair<Intent, Uri> createTakePictureIntent(Context context, Track.Id trackId) {
|
||||||
File dir = FileUtils.getPhotoDir(context, trackId);
|
File dir = FileUtils.getPhotoDir(context, trackId);
|
||||||
|
|
||||||
String fileName = SimpleDateFormat.getDateTimeInstance().format(new Date());
|
String fileName = SimpleDateFormat.getDateTimeInstance().format(new Date());
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user