mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-12 13:53:07 +02:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16c20287ca | |||
| a733d87c37 | |||
| 79d8ba9ef8 | |||
| 3ee7d4504c | |||
| 579509aad8 | |||
| 24ff73ab06 | |||
| 60d5e7e515 | |||
| c610758ae1 | |||
| 17d2755844 | |||
| 0ab14e0f3d | |||
| bcbaf4985a | |||
| b2e8713db0 | |||
| af60e1fdfb | |||
| 75043325ff |
@@ -0,0 +1,10 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "gradle"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
+11
-7
@@ -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 3530
|
versionCode 3544
|
||||||
versionName "v3.9.1"
|
versionName "v3.9.3"
|
||||||
|
|
||||||
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.0'
|
||||||
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.4.6'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -74,7 +74,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,18 +88,18 @@ 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 Waypoint.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);
|
||||||
@@ -113,22 +113,22 @@ public class SearchEngineTest {
|
|||||||
waypoint.setTrackId(trackId);
|
waypoint.setTrackId(trackId);
|
||||||
|
|
||||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
Uri uri = providerUtils.insertWaypoint(waypoint);
|
||||||
return ContentUris.parseId(uri);
|
return new Waypoint.Id(ContentUris.parseId(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertWaypoint(String title, String description, String category) {
|
private Waypoint.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 Waypoint.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 Waypoint.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 Waypoint.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 +143,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 +168,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");
|
Waypoint.Id descriptionMatchId = insertWaypoint("bb", "aa", "cc");
|
||||||
long categoryMatchId = insertWaypoint("bb", "cc", "aa");
|
Waypoint.Id categoryMatchId = insertWaypoint("bb", "cc", "aa");
|
||||||
long titleMatchId = insertWaypoint("aa", "bb", "cc");
|
Waypoint.Id titleMatchId = insertWaypoint("aa", "bb", "cc");
|
||||||
long titleCategoryMatchId = insertWaypoint("aa", "bb", "ca");
|
Waypoint.Id titleCategoryMatchId = insertWaypoint("aa", "bb", "ca");
|
||||||
long titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc");
|
Waypoint.Id titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc");
|
||||||
long allMatchId = insertWaypoint("aa", "ba", "ca");
|
Waypoint.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,13 +190,13 @@ 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");
|
Waypoint.Id descriptionWaypointId = insertWaypoint("bb", "aa", "cc");
|
||||||
insertWaypoint("bb", "cc", "dd");
|
insertWaypoint("bb", "cc", "dd");
|
||||||
long titleWaypointId = insertWaypoint("aa", "bb", "cc");
|
Waypoint.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.
|
||||||
@@ -209,11 +209,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);
|
Waypoint.Id farFarAwayId = insertWaypoint("aa", 0.3);
|
||||||
long nearId = insertWaypoint("ab", 0.1);
|
Waypoint.Id nearId = insertWaypoint("ab", 0.1);
|
||||||
long farId = insertWaypoint("ac", 0.2);
|
Waypoint.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 +222,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 +236,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);
|
Waypoint.Id oldestId = insertWaypoint("aa", 2);
|
||||||
long recentId = insertWaypoint("ab", 0);
|
Waypoint.Id recentId = insertWaypoint("ab", 0);
|
||||||
long oldId = insertWaypoint("ac", 1);
|
Waypoint.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 +250,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,24 +263,29 @@ 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);
|
Waypoint.Id otherId = insertWaypoint("aa", 1, new Track.Id(456));
|
||||||
long currentId = insertWaypoint("ab", 1, 123);
|
Waypoint.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);
|
Assert.assertNotNull("Not a track", result.track);
|
||||||
Assert.assertNull("Ambiguous result", result.waypoint);
|
Assert.assertNull("Ambiguous result", result.waypoint);
|
||||||
Assert.assertEquals(trackId, result.track.getId());
|
Assert.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];
|
||||||
|
for (int i = 0; i < trackIds.length; i++) {
|
||||||
|
longTrackIds[i] = trackIds[i].getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
String errMsg = "Expected IDs=" + Arrays.toString(longTrackIds) + "; results=" + results;
|
||||||
Assert.assertEquals(results.size(), trackIds.length);
|
Assert.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);
|
||||||
@@ -290,14 +295,19 @@ public class SearchEngineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertWaypointResult(long waypointId, ScoredResult result) {
|
private void assertWaypointResult(Waypoint.Id waypointId, ScoredResult result) {
|
||||||
Assert.assertNotNull("Not a waypoint", result.waypoint);
|
Assert.assertNotNull("Not a waypoint", result.waypoint);
|
||||||
Assert.assertNull("Ambiguous result", result.track);
|
Assert.assertNull("Ambiguous result", result.track);
|
||||||
Assert.assertEquals(waypointId, result.waypoint.getId());
|
Assert.assertEquals(waypointId, result.waypoint.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertWaypointResults(List<ScoredResult> results, long... waypointIds) {
|
private void assertWaypointResults(List<ScoredResult> results, Waypoint.Id... waypointIds) {
|
||||||
String errMsg = "Expected IDs=" + Arrays.toString(waypointIds) + "; results=" + results;
|
long[] longWaypointIds = new long[waypointIds.length];
|
||||||
|
for (int i = 0; i < waypointIds.length; i++) {
|
||||||
|
longWaypointIds[i] = waypointIds[i].getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
String errMsg = "Expected IDs=" + Arrays.toString(longWaypointIds) + "; results=" + results;
|
||||||
Assert.assertEquals(results.size(), waypointIds.length);
|
Assert.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);
|
||||||
|
|||||||
@@ -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,7 +93,7 @@ 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 Waypoint 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);
|
||||||
|
|||||||
+106
-101
@@ -83,39 +83,39 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_noPoints() {
|
public void testLocationIterator_noPoints() {
|
||||||
testIterator(1, 0, 1, false);
|
testIterator(new Track.Id(1), 0, 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_noBatchAscending() {
|
public void testLocationIterator_noBatchAscending() {
|
||||||
testIterator(1, 50, 100, false);
|
testIterator(new Track.Id(1), 50, 100, false);
|
||||||
testIterator(2, 50, 50, false);
|
testIterator(new Track.Id(2), 50, 50, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_noBatchDescending() {
|
public void testLocationIterator_noBatchDescending() {
|
||||||
testIterator(1, 50, 100, true);
|
testIterator(new Track.Id(1), 50, 100, true);
|
||||||
testIterator(2, 50, 50, true);
|
testIterator(new Track.Id(2), 50, 50, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_batchAscending() {
|
public void testLocationIterator_batchAscending() {
|
||||||
testIterator(1, 50, 11, false);
|
testIterator(new Track.Id(1), 50, 11, false);
|
||||||
testIterator(2, 50, 25, false);
|
testIterator(new Track.Id(2), 50, 25, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_batchDescending() {
|
public void testLocationIterator_batchDescending() {
|
||||||
testIterator(1, 50, 11, true);
|
testIterator(new Track.Id(1), 50, 11, true);
|
||||||
testIterator(2, 50, 25, true);
|
testIterator(new Track.Id(2), 50, 25, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_largeTrack() {
|
public void testLocationIterator_largeTrack() {
|
||||||
testIterator(1, 20000, 2000, false);
|
testIterator(new Track.Id(1), 20000, 2000, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testIterator(long trackId, int numPoints, int batchSize, boolean descending) {
|
private void testIterator(Track.Id trackId, int numPoints, int batchSize, boolean descending) {
|
||||||
long lastPointId = initializeTrack(trackId, numPoints);
|
long lastPointId = initializeTrack(trackId, numPoints);
|
||||||
contentProviderUtils.setDefaultCursorBatchSize(batchSize);
|
contentProviderUtils.setDefaultCursorBatchSize(batchSize);
|
||||||
List<TrackPoint> locations = new ArrayList<>(numPoints);
|
List<TrackPoint> locations = new ArrayList<>(numPoints);
|
||||||
@@ -132,10 +132,10 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long initializeTrack(long id, int numPoints) {
|
private long initializeTrack(Track.Id id, int numPoints) {
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
track.setId(id);
|
track.setId(id);
|
||||||
track.setName("Test: " + id);
|
track.setName("Test: " + id.getId());
|
||||||
contentProviderUtils.insertTrack(track);
|
contentProviderUtils.insertTrack(track);
|
||||||
track = contentProviderUtils.getTrack(id);
|
track = contentProviderUtils.getTrack(id);
|
||||||
Assert.assertNotNull(track);
|
Assert.assertNotNull(track);
|
||||||
@@ -173,13 +173,13 @@ public class CustomContentProviderUtilsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCreateTrack() {
|
public void testCreateTrack() {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
|
|
||||||
int columnIndex = 1;
|
int columnIndex = 1;
|
||||||
// Id
|
// Id
|
||||||
when(cursorMock.getColumnIndexOrThrow(TracksColumns._ID)).thenReturn(columnIndex);
|
when(cursorMock.getColumnIndexOrThrow(TracksColumns._ID)).thenReturn(columnIndex);
|
||||||
when(cursorMock.isNull(columnIndex)).thenReturn(false);
|
when(cursorMock.isNull(columnIndex)).thenReturn(false);
|
||||||
when(cursorMock.getLong(columnIndex)).thenReturn(trackId);
|
when(cursorMock.getLong(columnIndex)).thenReturn(trackId.getId());
|
||||||
|
|
||||||
//Uuid
|
//Uuid
|
||||||
columnIndex++;
|
columnIndex++;
|
||||||
@@ -189,7 +189,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
// Name
|
// Name
|
||||||
columnIndex++;
|
columnIndex++;
|
||||||
String name = NAME_PREFIX + trackId;
|
String name = NAME_PREFIX + trackId.getId();
|
||||||
when(cursorMock.getColumnIndexOrThrow(TracksColumns.NAME)).thenReturn(columnIndex);
|
when(cursorMock.getColumnIndexOrThrow(TracksColumns.NAME)).thenReturn(columnIndex);
|
||||||
when(cursorMock.isNull(columnIndex)).thenReturn(false);
|
when(cursorMock.isNull(columnIndex)).thenReturn(false);
|
||||||
when(cursorMock.getString(columnIndex)).thenReturn(name);
|
when(cursorMock.getString(columnIndex)).thenReturn(name);
|
||||||
@@ -205,7 +205,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testDeleteAllTracks() {
|
public void testDeleteAllTracks() {
|
||||||
// Insert track, points and waypoint at first.
|
// Insert track, points and waypoint at first.
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||||
@@ -235,7 +235,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testDeleteAllTracks_withWaypointAndPhoto() throws IOException {
|
public void testDeleteAllTracks_withWaypointAndPhoto() throws IOException {
|
||||||
// Insert track, points and waypoint with photo at first.
|
// Insert track, points and waypoint with photo at first.
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
||||||
@@ -268,20 +268,23 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#deleteTrack(Context, long)}.
|
* Tests the method {@link ContentProviderUtils#deleteTrack(Context, Track.Id)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteTrack() {
|
public void testDeleteTrack() {
|
||||||
// Insert three tracks, points of two tracks and way point of one track.
|
// Insert three tracks, points of two tracks and way point of one track.
|
||||||
|
long random = System.currentTimeMillis();
|
||||||
|
Track.Id trackId1 = new Track.Id(random);
|
||||||
|
Track.Id trackId2 = new Track.Id(random + 1);
|
||||||
|
Track.Id trackId3 = new Track.Id(random + 2);
|
||||||
|
|
||||||
long trackId = System.currentTimeMillis();
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId1, 0);
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 0);
|
|
||||||
|
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId + 1, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId2, 10);
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId + 2, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId3, 10);
|
||||||
|
|
||||||
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId + 1));
|
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId2));
|
||||||
waypoint.setTrackId(trackId);
|
waypoint.setTrackId(trackId1);
|
||||||
contentProviderUtils.insertWaypoint(waypoint);
|
contentProviderUtils.insertWaypoint(waypoint);
|
||||||
|
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
@@ -292,7 +295,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Cursor waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null, null, WaypointsColumns._ID);
|
Cursor waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null, null, WaypointsColumns._ID);
|
||||||
Assert.assertEquals(1, waypointCursor.getCount());
|
Assert.assertEquals(1, waypointCursor.getCount());
|
||||||
// Delete one track.
|
// Delete one track.
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId1);
|
||||||
// Check whether all data of a track has been deleted.
|
// Check whether all data of a track has been deleted.
|
||||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||||
Assert.assertEquals(2, tracksCursor.getCount());
|
Assert.assertEquals(2, tracksCursor.getCount());
|
||||||
@@ -303,26 +306,30 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#deleteTrack(Context, long)}.
|
* Tests the method {@link ContentProviderUtils#deleteTrack(Context, Track.Id)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteTrack_withWaypointPhoto() throws IOException {
|
public void testDeleteTrack_withWaypointPhoto() throws IOException {
|
||||||
// Insert three tracks.
|
// Insert three tracks.
|
||||||
long trackId = System.currentTimeMillis();
|
long random = System.currentTimeMillis();
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
Track.Id trackId1 = new Track.Id(random);
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId + 1, 10);
|
Track.Id trackId2 = new Track.Id(random + 1);
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId + 2, 10);
|
Track.Id trackId3 = new Track.Id(random + 2);
|
||||||
|
|
||||||
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId1, 10);
|
||||||
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId2, 10);
|
||||||
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId3, 10);
|
||||||
|
|
||||||
// Insert a waypoint in tracks trackId and trackId + 1.
|
// Insert a waypoint in tracks trackId and trackId + 1.
|
||||||
TrackPoint trackPoint1 = contentProviderUtils.getLastValidTrackPoint(trackId);
|
TrackPoint trackPoint1 = contentProviderUtils.getLastValidTrackPoint(trackId1);
|
||||||
Waypoint waypoint1 = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint1.getLocation());
|
Waypoint waypoint1 = TestDataUtil.createWaypointWithPhoto(context, trackId1, trackPoint1.getLocation());
|
||||||
contentProviderUtils.insertWaypoint(waypoint1);
|
contentProviderUtils.insertWaypoint(waypoint1);
|
||||||
File dir1 = FileUtils.getPhotoDir(context, trackId);
|
File dir1 = FileUtils.getPhotoDir(context, trackId1);
|
||||||
|
|
||||||
TrackPoint trackPoint2 = contentProviderUtils.getLastValidTrackPoint(trackId + 1);
|
TrackPoint trackPoint2 = contentProviderUtils.getLastValidTrackPoint(trackId2);
|
||||||
Waypoint waypoint2 = TestDataUtil.createWaypointWithPhoto(context, trackId + 1, trackPoint2.getLocation());
|
Waypoint waypoint2 = TestDataUtil.createWaypointWithPhoto(context, trackId2, trackPoint2.getLocation());
|
||||||
contentProviderUtils.insertWaypoint(waypoint2);
|
contentProviderUtils.insertWaypoint(waypoint2);
|
||||||
File dir2 = FileUtils.getPhotoDir(context, trackId + 1);
|
File dir2 = FileUtils.getPhotoDir(context, trackId2);
|
||||||
|
|
||||||
// Check.
|
// Check.
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
@@ -340,7 +347,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Assert.assertEquals(1, dir2.list().length);
|
Assert.assertEquals(1, dir2.list().length);
|
||||||
Assert.assertTrue(dir2.exists());
|
Assert.assertTrue(dir2.exists());
|
||||||
// Delete one track.
|
// Delete one track.
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId1);
|
||||||
// Check whether all data of a track has been deleted.
|
// Check whether all data of a track has been deleted.
|
||||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||||
Assert.assertEquals(2, tracksCursor.getCount());
|
Assert.assertEquals(2, tracksCursor.getCount());
|
||||||
@@ -353,17 +360,17 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getAllTracks()}
|
* Tests the method {@link ContentProviderUtils#getTracks()}
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetAllTracks() {
|
public void testGetAllTracks() {
|
||||||
// given
|
// given
|
||||||
int initialTrackNumber = contentProviderUtils.getAllTracks().size();
|
int initialTrackNumber = contentProviderUtils.getTracks().size();
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
contentProviderUtils.insertTrack(TestDataUtil.createTrack(trackId));
|
contentProviderUtils.insertTrack(TestDataUtil.createTrack(trackId));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
List<Track> allTracks = contentProviderUtils.getAllTracks();
|
List<Track> allTracks = contentProviderUtils.getTracks();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(initialTrackNumber + 1, allTracks.size());
|
Assert.assertEquals(initialTrackNumber + 1, allTracks.size());
|
||||||
@@ -375,18 +382,18 @@ public class CustomContentProviderUtilsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetLastTrack() {
|
public void testGetLastTrack() {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
contentProviderUtils.insertTrack(TestDataUtil.createTrack(trackId));
|
contentProviderUtils.insertTrack(TestDataUtil.createTrack(trackId));
|
||||||
Assert.assertEquals(trackId, contentProviderUtils.getLastTrack().getId());
|
Assert.assertEquals(trackId, contentProviderUtils.getLastTrack().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getTrack(long)}
|
* Tests the method {@link ContentProviderUtils#getTrack(Track.Id)}
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetTrack_by_id() {
|
public void testGetTrack_by_id() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
contentProviderUtils.insertTrack(TestDataUtil.createTrack(trackId));
|
contentProviderUtils.insertTrack(TestDataUtil.createTrack(trackId));
|
||||||
|
|
||||||
// when / then
|
// when / then
|
||||||
@@ -394,12 +401,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getTrack(long)}
|
* Tests the method {@link ContentProviderUtils#getTrack(Track.Id)}
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetTrack_by_uuid() {
|
public void testGetTrack_by_uuid() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Track track = TestDataUtil.createTrack(trackId);
|
Track track = TestDataUtil.createTrack(trackId);
|
||||||
contentProviderUtils.insertTrack(track);
|
contentProviderUtils.insertTrack(track);
|
||||||
|
|
||||||
@@ -413,7 +420,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testUpdateTrack() {
|
public void testUpdateTrack() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Track track = TestDataUtil.createTrack(trackId);
|
Track track = TestDataUtil.createTrack(trackId);
|
||||||
String nameOld = "name1";
|
String nameOld = "name1";
|
||||||
String nameNew = "name2";
|
String nameNew = "name2";
|
||||||
@@ -432,7 +439,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCreateContentValues_waypoint() {
|
public void testCreateContentValues_waypoint() {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
||||||
|
|
||||||
// Bottom
|
// Bottom
|
||||||
@@ -458,10 +465,10 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(contentResolverMock);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(contentResolverMock);
|
||||||
|
|
||||||
long waypointId = System.currentTimeMillis();
|
Waypoint.Id waypointId = new Waypoint.Id(System.currentTimeMillis());
|
||||||
waypoint.setId(waypointId);
|
waypoint.setId(waypointId);
|
||||||
ContentValues contentValues = contentProviderUtils.createContentValues(waypoint);
|
ContentValues contentValues = contentProviderUtils.createContentValues(waypoint);
|
||||||
Assert.assertEquals(waypointId, contentValues.get(WaypointsColumns._ID));
|
Assert.assertEquals(waypointId.getId(), contentValues.get(WaypointsColumns._ID));
|
||||||
Assert.assertEquals((int) (TestDataUtil.INITIAL_LONGITUDE * 1000000), contentValues.get(WaypointsColumns.LONGITUDE));
|
Assert.assertEquals((int) (TestDataUtil.INITIAL_LONGITUDE * 1000000), contentValues.get(WaypointsColumns.LONGITUDE));
|
||||||
Assert.assertEquals(TEST_DESC, contentValues.get(WaypointsColumns.DESCRIPTION));
|
Assert.assertEquals(TEST_DESC, contentValues.get(WaypointsColumns.DESCRIPTION));
|
||||||
}
|
}
|
||||||
@@ -495,19 +502,19 @@ public class CustomContentProviderUtilsTest {
|
|||||||
when(cursorMock.getLong(columnIndex++)).thenReturn(trackId);
|
when(cursorMock.getLong(columnIndex++)).thenReturn(trackId);
|
||||||
|
|
||||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursorMock);
|
Waypoint waypoint = contentProviderUtils.createWaypoint(cursorMock);
|
||||||
Assert.assertEquals(id, waypoint.getId());
|
Assert.assertEquals(id, waypoint.getId().getId());
|
||||||
Assert.assertEquals(name, waypoint.getName());
|
Assert.assertEquals(name, waypoint.getName());
|
||||||
Assert.assertEquals(trackId, waypoint.getTrackId());
|
Assert.assertEquals(trackId, waypoint.getTrackId().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method
|
* Tests the method
|
||||||
* {@link ContentProviderUtils#deleteWaypoint(Context, long)}
|
* {@link ContentProviderUtils#deleteWaypoint(Context, Waypoint.Id)}
|
||||||
* when there is only one waypoint in the track.
|
* when there is only one waypoint in the track.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteWaypoint_onlyOneWayPoint() {
|
public void testDeleteWaypoint_onlyOneWayPoint() {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
// Insert at first.
|
// Insert at first.
|
||||||
@@ -520,7 +527,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Assert.assertEquals(contentProviderUtils.getWaypointCount(trackId), 1);
|
Assert.assertEquals(contentProviderUtils.getWaypointCount(trackId), 1);
|
||||||
|
|
||||||
// Get waypoint id that needs to delete.
|
// Get waypoint id that needs to delete.
|
||||||
long waypoint1Id = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1));
|
Waypoint.Id waypoint1Id = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1)));
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
contentProviderUtils.deleteWaypoint(context, waypoint1Id);
|
contentProviderUtils.deleteWaypoint(context, waypoint1Id);
|
||||||
@@ -530,12 +537,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method
|
* Tests the method
|
||||||
* {@link ContentProviderUtils#deleteWaypoint(Context, long)}
|
* {@link ContentProviderUtils#deleteWaypoint(Context, Waypoint.Id)}
|
||||||
* when there is only one waypoint in the track.
|
* when there is only one waypoint in the track.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteWaypoint_onlyOneWayPointWithPhotoUrl() throws IOException {
|
public void testDeleteWaypoint_onlyOneWayPointWithPhotoUrl() throws IOException {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
// Insert at first.
|
// Insert at first.
|
||||||
@@ -547,7 +554,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Assert.assertEquals(contentProviderUtils.getWaypointCount(trackId), 1);
|
Assert.assertEquals(contentProviderUtils.getWaypointCount(trackId), 1);
|
||||||
|
|
||||||
// Get waypoint id that needs to delete.
|
// Get waypoint id that needs to delete.
|
||||||
long waypoint1Id = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1));
|
Waypoint.Id waypoint1Id = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1)));
|
||||||
|
|
||||||
// Check waypoint has photo and it's in the external storage.
|
// Check waypoint has photo and it's in the external storage.
|
||||||
Assert.assertTrue(waypoint1.hasPhoto());
|
Assert.assertTrue(waypoint1.hasPhoto());
|
||||||
@@ -565,11 +572,11 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#deleteWaypoint(Context, long)} when there is more than one waypoint in the track.
|
* Tests the method {@link ContentProviderUtils#deleteWaypoint(Context, Waypoint.Id)} when there is more than one waypoint in the track.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteWaypoint_hasNextWayPoint() {
|
public void testDeleteWaypoint_hasNextWayPoint() {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
// Track track = TestDataUtil.createTrackAndInsert(trackId, 10);
|
// Track track = TestDataUtil.createTrackAndInsert(trackId, 10);
|
||||||
@@ -592,12 +599,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Waypoint waypoint1 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
Waypoint waypoint1 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||||
waypoint1.setDescription(MOCK_DESC);
|
waypoint1.setDescription(MOCK_DESC);
|
||||||
waypoint1.setTrackId(trackId);
|
waypoint1.setTrackId(trackId);
|
||||||
long waypoint1Id = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1));
|
Waypoint.Id waypoint1Id = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint1)));
|
||||||
|
|
||||||
Waypoint waypoint2 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
Waypoint waypoint2 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||||
waypoint2.setDescription(MOCK_DESC);
|
waypoint2.setDescription(MOCK_DESC);
|
||||||
waypoint2.setTrackId(trackId);
|
waypoint2.setTrackId(trackId);
|
||||||
long waypoint2Id = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint2));
|
Waypoint.Id waypoint2Id = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint2)));
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
Assert.assertNotNull(contentProviderUtils.getWaypoint(waypoint1Id));
|
Assert.assertNotNull(contentProviderUtils.getWaypoint(waypoint1Id));
|
||||||
@@ -608,11 +615,11 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getNextWaypointNumber(long)}.
|
* Tests the method {@link ContentProviderUtils#getNextWaypointNumber(Track.Id)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetNextWaypointNumber() {
|
public void testGetNextWaypointNumber() {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
Waypoint waypoint1 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
Waypoint waypoint1 = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||||
@@ -633,17 +640,17 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#insertWaypoint(Waypoint)} and
|
* Tests the method {@link ContentProviderUtils#insertWaypoint(Waypoint)} and
|
||||||
* {@link ContentProviderUtils#getWaypoint(long)}.
|
* {@link ContentProviderUtils#getWaypoint(Waypoint.Id)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testInsertAndGetWaypoint() {
|
public void testInsertAndGetWaypoint() {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||||
waypoint.setDescription(TEST_DESC);
|
waypoint.setDescription(TEST_DESC);
|
||||||
waypoint.setTrackId(trackId);
|
waypoint.setTrackId(trackId);
|
||||||
long waypointId = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint));
|
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||||
|
|
||||||
Assert.assertEquals(TEST_DESC, contentProviderUtils.getWaypoint(waypointId).getDescription());
|
Assert.assertEquals(TEST_DESC, contentProviderUtils.getWaypoint(waypointId).getDescription());
|
||||||
}
|
}
|
||||||
@@ -653,14 +660,14 @@ public class CustomContentProviderUtilsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateWaypoint() {
|
public void testUpdateWaypoint() {
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
// Insert at first.
|
// Insert at first.
|
||||||
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
Waypoint waypoint = new Waypoint(contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||||
waypoint.setDescription(TEST_DESC);
|
waypoint.setDescription(TEST_DESC);
|
||||||
waypoint.setTrackId(trackId);
|
waypoint.setTrackId(trackId);
|
||||||
long waypointId = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint));
|
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
waypoint = contentProviderUtils.getWaypoint(waypointId);
|
waypoint = contentProviderUtils.getWaypoint(waypointId);
|
||||||
@@ -677,7 +684,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
public void testUpdateWaypoint_withPhoto() throws IOException {
|
public void testUpdateWaypoint_withPhoto() throws IOException {
|
||||||
// tests after update waypoint with photo the photo remains in the storage.
|
// tests after update waypoint with photo the photo remains in the storage.
|
||||||
|
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
// Insert at first.
|
// Insert at first.
|
||||||
@@ -685,9 +692,9 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Waypoint waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
Waypoint waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||||
waypoint.setDescription(TEST_DESC);
|
waypoint.setDescription(TEST_DESC);
|
||||||
waypoint.setTrackId(trackId);
|
waypoint.setTrackId(trackId);
|
||||||
long waypointId = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint));
|
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||||
|
|
||||||
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId);
|
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId.getId());
|
||||||
Assert.assertTrue(dir.exists());
|
Assert.assertTrue(dir.exists());
|
||||||
Assert.assertTrue(dir.isDirectory());
|
Assert.assertTrue(dir.isDirectory());
|
||||||
Assert.assertEquals(1, dir.list().length);
|
Assert.assertEquals(1, dir.list().length);
|
||||||
@@ -713,7 +720,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
public void testUpdateWaypoint_delPhotoAndDir() throws IOException {
|
public void testUpdateWaypoint_delPhotoAndDir() throws IOException {
|
||||||
// tests after update waypoint if user deletes the photo then file photo is deleted from the storage. Also empty directory is deleted.
|
// tests after update waypoint if user deletes the photo then file photo is deleted from the storage. Also empty directory is deleted.
|
||||||
|
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
// Insert at first.
|
// Insert at first.
|
||||||
@@ -721,9 +728,9 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Waypoint waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
Waypoint waypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||||
waypoint.setDescription(TEST_DESC);
|
waypoint.setDescription(TEST_DESC);
|
||||||
waypoint.setTrackId(trackId);
|
waypoint.setTrackId(trackId);
|
||||||
long waypointId = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint));
|
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||||
|
|
||||||
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId);
|
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId.getId());
|
||||||
Assert.assertTrue(dir.exists());
|
Assert.assertTrue(dir.exists());
|
||||||
Assert.assertTrue(dir.isDirectory());
|
Assert.assertTrue(dir.isDirectory());
|
||||||
Assert.assertEquals(1, dir.list().length);
|
Assert.assertEquals(1, dir.list().length);
|
||||||
@@ -748,7 +755,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
public void testUpdateWaypoint_delPhotoNotDir() throws IOException {
|
public void testUpdateWaypoint_delPhotoNotDir() throws IOException {
|
||||||
// tests after update waypoint if user deletes the photo then file photo is deleted from the storage. Directory remains if there are more photos from other waypoints.
|
// tests after update waypoint if user deletes the photo then file photo is deleted from the storage. Directory remains if there are more photos from other waypoints.
|
||||||
|
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
// Insert two waypoints with photos.
|
// Insert two waypoints with photos.
|
||||||
@@ -759,10 +766,10 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Waypoint otherWaypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
Waypoint otherWaypoint = TestDataUtil.createWaypointWithPhoto(context, trackId, trackPoint.getLocation());
|
||||||
otherWaypoint.setDescription(TEST_DESC);
|
otherWaypoint.setDescription(TEST_DESC);
|
||||||
otherWaypoint.setTrackId(trackId);
|
otherWaypoint.setTrackId(trackId);
|
||||||
long waypointId = ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint));
|
Waypoint.Id waypointId = new Waypoint.Id(ContentUris.parseId(contentProviderUtils.insertWaypoint(waypoint)));
|
||||||
long otherWaypointId = ContentUris.parseId(contentProviderUtils.insertWaypoint(otherWaypoint));
|
contentProviderUtils.insertWaypoint(otherWaypoint);
|
||||||
|
|
||||||
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId);
|
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId.getId());
|
||||||
Assert.assertTrue(dir.exists());
|
Assert.assertTrue(dir.exists());
|
||||||
Assert.assertTrue(dir.isDirectory());
|
Assert.assertTrue(dir.isDirectory());
|
||||||
Assert.assertEquals(2, dir.list().length);
|
Assert.assertEquals(2, dir.list().length);
|
||||||
@@ -780,12 +787,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#bulkInsertTrackPoint(TrackPoint[], long)}.
|
* Tests the method {@link ContentProviderUtils#bulkInsertTrackPoint(TrackPoint[], Track.Id)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testBulkInsertTrackPoint() {
|
public void testBulkInsertTrackPoint() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
||||||
TestDataUtil.insertTrackWithLocations(contentProviderUtils, track.first, track.second);
|
TestDataUtil.insertTrackWithLocations(contentProviderUtils, track.first, track.second);
|
||||||
|
|
||||||
@@ -841,12 +848,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method
|
* Tests the method
|
||||||
* {@link ContentProviderUtils#insertTrackPoint(TrackPoint, long)}.
|
* {@link ContentProviderUtils#insertTrackPoint(TrackPoint, Track.Id)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testInsertTrackPoint() {
|
public void testInsertTrackPoint() {
|
||||||
// Insert track, point at first.
|
// Insert track, point at first.
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
|
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
|
||||||
@@ -856,7 +863,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testInsertAndLoadTrackPoint() {
|
public void testInsertAndLoadTrackPoint() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
TrackPoint trackPoint = TestDataUtil.createTrackPoint(5);
|
TrackPoint trackPoint = TestDataUtil.createTrackPoint(5);
|
||||||
@@ -876,12 +883,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getLastValidTrackPoint(long)}.
|
* Tests the method {@link ContentProviderUtils#getLastValidTrackPoint(Track.Id)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetLastValidTrackPoint() {
|
public void testGetLastValidTrackPoint() {
|
||||||
// Insert track, points at first.
|
// Insert track, points at first.
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
TrackPoint lastTrackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
TrackPoint lastTrackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
|
||||||
@@ -889,12 +896,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getTrackPointCursor(long, long, int, boolean)} in descending.
|
* Tests the method {@link ContentProviderUtils#getTrackPointCursor(Track.Id, long, int, boolean)} in descending.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetTrackPointCursor_desc() {
|
public void testGetTrackPointCursor_desc() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
||||||
contentProviderUtils.insertTrack(track.first);
|
contentProviderUtils.insertTrack(track.first);
|
||||||
|
|
||||||
@@ -911,12 +918,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getTrackPointCursor(long, long, int, boolean)} in ascending.
|
* Tests the method {@link ContentProviderUtils#getTrackPointCursor(Track.Id, long, int, boolean)} in ascending.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetTrackPointCursor_asc() {
|
public void testGetTrackPointCursor_asc() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
||||||
contentProviderUtils.insertTrack(track.first);
|
contentProviderUtils.insertTrack(track.first);
|
||||||
|
|
||||||
@@ -933,12 +940,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getTrackPointLocationIterator(long, long, boolean)} in descending.
|
* Tests the method {@link ContentProviderUtils#getTrackPointLocationIterator(Track.Id, long, boolean)} in descending.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetTrackPointLocationIterator_desc() {
|
public void testGetTrackPointLocationIterator_desc() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
||||||
contentProviderUtils.insertTrack(track.first);
|
contentProviderUtils.insertTrack(track.first);
|
||||||
|
|
||||||
@@ -962,12 +969,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#getTrackPointLocationIterator(long, long, boolean)} in ascending.
|
* Tests the method {@link ContentProviderUtils#getTrackPointLocationIterator(Track.Id, long, boolean)} in ascending.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetTrackPointLocationIterator_asc() {
|
public void testGetTrackPointLocationIterator_asc() {
|
||||||
// given
|
// given
|
||||||
long trackId = System.currentTimeMillis();
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
Pair<Track, TrackPoint[]> track = TestDataUtil.createTrack(trackId, 10);
|
||||||
contentProviderUtils.insertTrack(track.first);
|
contentProviderUtils.insertTrack(track.first);
|
||||||
|
|
||||||
@@ -995,7 +1002,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
/**
|
/**
|
||||||
* Checks the value of a location.
|
* Checks the value of a location.
|
||||||
*
|
*
|
||||||
* @param i the index of this location which created in the method {@link TestDataUtil#createTrack(long, int)}
|
* @param i the index of this location which created in the method {@link TestDataUtil#createTrack(Track.Id, int)}
|
||||||
* @param location the location to be checked
|
* @param location the location to be checked
|
||||||
*/
|
*/
|
||||||
private void checkLocation(int i, Location location) {
|
private void checkLocation(int i, Location location) {
|
||||||
@@ -1005,12 +1012,10 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Assert.assertEquals(i * TestDataUtil.ALTITUDE_INTERVAL, location.getAltitude(), 0.01);
|
Assert.assertEquals(i * TestDataUtil.ALTITUDE_INTERVAL, location.getAltitude(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFormatIdListForUri() {
|
public void testFormatIdListForUri() {
|
||||||
Assert.assertEquals("", ContentProviderUtils.formatIdListForUri(new long[]{}));
|
Assert.assertEquals("", ContentProviderUtils.formatIdListForUri());
|
||||||
Assert.assertEquals("12", ContentProviderUtils.formatIdListForUri(new long[]{12}));
|
Assert.assertEquals("12", ContentProviderUtils.formatIdListForUri(new Track.Id(12)));
|
||||||
Assert.assertEquals("42,43,44", ContentProviderUtils.formatIdListForUri(new long[]{42, 43, 44}));
|
Assert.assertEquals("42,43,44", ContentProviderUtils.formatIdListForUri(new Track.Id(42), new Track.Id(43), new Track.Id(44)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-4
@@ -6,6 +6,10 @@ import android.util.Pair;
|
|||||||
import org.junit.Assert;
|
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;
|
||||||
|
|
||||||
public class ShareContentProviderTest {
|
public class ShareContentProviderTest {
|
||||||
@@ -14,20 +18,25 @@ public class ShareContentProviderTest {
|
|||||||
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));
|
Assert.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));
|
Assert.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);
|
Assert.assertEquals(Uri.parse("content://de.dennisguse.opentracks.debug.content/tracks/kml_only_track/1/..%2F..%2F%261%3D1.kml"), shareURIandMIME.first);
|
||||||
|
|||||||
+3
-3
@@ -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,7 +111,7 @@ 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.insertWaypoint(any())).thenReturn(WAYPOINT_ID_O_URI);
|
||||||
|
|||||||
+2
-2
@@ -56,8 +56,8 @@ public class ExportImportTest {
|
|||||||
private final List<Waypoint> waypoints = new ArrayList<>();
|
private final List<Waypoint> waypoints = 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() {
|
||||||
|
|||||||
+25
-16
@@ -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;
|
||||||
@@ -33,6 +34,7 @@ import androidx.test.rule.ServiceTestRule;
|
|||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
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;
|
||||||
@@ -69,10 +71,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);
|
||||||
@@ -125,7 +134,7 @@ public class TrackRecordingServiceTest {
|
|||||||
@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());
|
Assert.assertTrue(tracks.isEmpty());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -136,7 +145,7 @@ 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());
|
Assert.assertFalse(service.isRecording());
|
||||||
Assert.assertEquals(-1L, service.getRecordingTrackId());
|
Assert.assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -150,7 +159,7 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
Assert.assertFalse(service.isRecording());
|
||||||
Assert.assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, service.getRecordingTrackId());
|
Assert.assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -234,7 +243,7 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(service.isRecording());
|
Assert.assertFalse(service.isRecording());
|
||||||
Assert.assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, service.getRecordingTrackId());
|
Assert.assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -245,13 +254,13 @@ public class TrackRecordingServiceTest {
|
|||||||
service.startNewTrack();
|
service.startNewTrack();
|
||||||
Assert.assertTrue(service.isRecording());
|
Assert.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);
|
Assert.assertNull(newTrackId);
|
||||||
|
|
||||||
Assert.assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
Assert.assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
||||||
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
Assert.assertEquals(trackId, service.getRecordingTrackId());
|
||||||
@@ -270,7 +279,7 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertFalse(PreferencesUtils.isRecording(context));
|
Assert.assertFalse(PreferencesUtils.isRecording(context));
|
||||||
Assert.assertEquals(PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, service.getRecordingTrackId());
|
Assert.assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -281,10 +290,10 @@ public class TrackRecordingServiceTest {
|
|||||||
Assert.assertFalse(service.isRecording());
|
Assert.assertFalse(service.isRecording());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
long waypointId = service.insertWaypoint(null, null, null, null);
|
Waypoint.Id waypointId = service.insertWaypoint(null, null, null, null);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertEquals(-1L, waypointId);
|
Assert.assertNull(waypointId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -295,10 +304,10 @@ public class TrackRecordingServiceTest {
|
|||||||
service.startNewTrack();
|
service.startNewTrack();
|
||||||
Assert.assertTrue(service.isRecording());
|
Assert.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);
|
Waypoint.Id waypointId = service.insertWaypoint(null, null, null, null);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Assert.assertNotEquals(-1L, waypointId);
|
Assert.assertNotEquals(-1L, waypointId);
|
||||||
@@ -313,15 +322,15 @@ public class TrackRecordingServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addTrack(Track track, boolean isRecording) {
|
private void addTrack(Track track, boolean isRecording) {
|
||||||
Assert.assertTrue(track.getId() >= 0);
|
Assert.assertTrue(track.getId().isValid());
|
||||||
contentProviderUtils.insertTrack(track);
|
contentProviderUtils.insertTrack(track);
|
||||||
Assert.assertEquals(track.getId(), contentProviderUtils.getTrack(track.getId()).getId());
|
Assert.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");
|
||||||
|
|||||||
+7
-6
@@ -23,6 +23,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;
|
||||||
@@ -89,7 +90,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);
|
||||||
@@ -113,7 +114,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
@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);
|
||||||
@@ -155,7 +156,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);
|
||||||
@@ -181,7 +182,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
@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);
|
||||||
@@ -209,7 +210,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) {
|
||||||
|
|
||||||
@@ -253,7 +254,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
@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);
|
||||||
|
|||||||
+10
-10
@@ -187,7 +187,7 @@ 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());
|
Assert.assertTrue(tracks.isEmpty());
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
@@ -197,14 +197,14 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
Assert.assertFalse(service.isRecording());
|
Assert.assertFalse(service.isRecording());
|
||||||
|
|
||||||
// Start a track.
|
// Start a track.
|
||||||
long id = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
Assert.assertTrue(id >= 0);
|
Assert.assertTrue(trackId.isValid());
|
||||||
Assert.assertTrue(service.isRecording());
|
Assert.assertTrue(service.isRecording());
|
||||||
Track track = contentProviderUtils.getTrack(id);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
Assert.assertNotNull(track);
|
Assert.assertNotNull(track);
|
||||||
Assert.assertEquals(id, track.getId());
|
Assert.assertEquals(trackId, track.getId());
|
||||||
Assert.assertEquals(id, PreferencesUtils.getRecordingTrackId(context));
|
Assert.assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
||||||
Assert.assertEquals(id, service.getRecordingTrackId());
|
Assert.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();
|
||||||
@@ -228,10 +228,10 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
// 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());
|
Assert.assertFalse(service.isRecording());
|
||||||
Assert.assertEquals(-1L, service.getRecordingTrackId());
|
Assert.assertNull(service.getRecordingTrackId());
|
||||||
track = contentProviderUtils.getTrack(id);
|
track = contentProviderUtils.getTrack(trackId);
|
||||||
Assert.assertNotNull(track);
|
Assert.assertNotNull(track);
|
||||||
Assert.assertEquals(id, track.getId());
|
Assert.assertEquals(trackId, track.getId());
|
||||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||||
Assert.assertNotNull(trackStatistics);
|
Assert.assertNotNull(trackStatistics);
|
||||||
Assert.assertTrue(trackStatistics.getStartTime_ms() > 0);
|
Assert.assertTrue(trackStatistics.getStartTime_ms() > 0);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ 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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link TrackNameUtils}.
|
* Tests {@link TrackNameUtils}.
|
||||||
@@ -39,7 +40,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();
|
||||||
@@ -69,6 +70,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));
|
Assert.assertEquals("Track " + TRACK_ID.getId(), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<Waypoint.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);
|
Waypoint.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);
|
Waypoint waypoint = contentProviderUtils.getWaypoint(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.getWaypointCursor(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);
|
Waypoint currentMarker = contentProviderUtils.createWaypoint(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,6 +42,7 @@ 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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
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.services.TrackRecordingServiceConnection;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||||
@@ -64,7 +65,7 @@ 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 Waypoint waypoint;
|
||||||
|
|
||||||
@@ -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);
|
Waypoint.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).getNextWaypointNumber(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).getWaypoint(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ 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.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
import de.dennisguse.opentracks.content.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;
|
||||||
@@ -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,19 +112,19 @@ 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 Waypoint.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) {
|
||||||
@@ -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.getWaypointsLoader(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) {
|
||||||
|
Waypoint.Id[] waypointIds = new Waypoint.Id[longWaypointIds.length];
|
||||||
|
for (int i = 0; i < longWaypointIds.length; i++) {
|
||||||
|
waypointIds[i] = new Waypoint.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.getWaypoint(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++) {
|
||||||
|
|||||||
@@ -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,7 +203,7 @@ 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);
|
Long markerId = (Long) 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) {
|
||||||
@@ -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);
|
Waypoint.Id waypointId = (Waypoint.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);
|
||||||
|
|
||||||
@@ -372,8 +372,8 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
|
|||||||
|
|
||||||
//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();
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import android.util.Pair;
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||||
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;
|
||||||
@@ -26,7 +29,7 @@ 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);
|
showTrackTrackfileFormat(this, trackFileFormat, trackIds);
|
||||||
|
|
||||||
@@ -39,14 +42,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 showTrackTrackfileFormat(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]);
|
intent.putExtra(TrackPointsColumns.TRACKID, trackIds.toArray(new Track.Id[0])[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,7 +262,7 @@ 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 == recordingTrackId;
|
||||||
String icon = cursor.getString(iconIndex);
|
String icon = cursor.getString(iconIndex);
|
||||||
int iconId = TrackIconUtils.getIconDrawable(icon);
|
int iconId = TrackIconUtils.getIconDrawable(icon);
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
private ViewPager pager;
|
private ViewPager pager;
|
||||||
|
|
||||||
// From intent.
|
// From intent.
|
||||||
private long trackId;
|
private Track.Id trackId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -133,7 +133,7 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
// Update UI
|
// Update UI
|
||||||
this.invalidateOptionsMenu();
|
this.invalidateOptionsMenu();
|
||||||
|
|
||||||
if (trackId != -1L) {
|
if (trackId.isValid()) {
|
||||||
trackDataHub.loadTrack(trackId);
|
trackDataHub.loadTrack(trackId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,12 +182,12 @@ 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, trackId);
|
||||||
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, 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)
|
||||||
@@ -200,7 +200,7 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
|
|||||||
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(trackId);
|
||||||
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)
|
||||||
@@ -238,12 +238,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);
|
trackId = intent.getParcelableExtra(EXTRA_TRACK_ID);
|
||||||
|
|
||||||
long markerId = intent.getLongExtra(EXTRA_MARKER_ID, -1L);
|
Waypoint.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);
|
Waypoint waypoint = contentProviderUtils.getWaypoint(waypointId);
|
||||||
if (waypoint == null) {
|
if (waypoint == null) {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
@@ -251,7 +251,7 @@ 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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ 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;
|
||||||
@@ -78,7 +78,7 @@ 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();
|
||||||
} else {
|
} else {
|
||||||
@@ -161,13 +161,14 @@ 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);
|
trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID);
|
||||||
if (trackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT && contentProviderUtils.getTrack(trackId) == null) {
|
if (trackId != null && contentProviderUtils.getTrack(trackId) == null) {
|
||||||
|
Log.w(TAG, "TrackId does not exists; cannot continue the recording.");
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +248,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 +266,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 +315,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)
|
||||||
|
|||||||
@@ -123,8 +123,8 @@ public class SearchEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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.waypoint.getId().getId();
|
||||||
long id2 = r2.track != null ? r2.track.getId() : r2.waypoint.getId();
|
long id2 = r2.track != null ? r2.track.getId().getId() : r2.waypoint.getId().getId();
|
||||||
long idDiff = id2 - id1;
|
long idDiff = id2 - id1;
|
||||||
return Long.signum(idDiff);
|
return Long.signum(idDiff);
|
||||||
};
|
};
|
||||||
@@ -290,7 +290,7 @@ public class SearchEngine {
|
|||||||
score *= getTimeBoost(query, location.getTime());
|
score *= getTimeBoost(query, location.getTime());
|
||||||
|
|
||||||
// Score waypoints in the currently-selected track higher (searching inside the current track).
|
// Score waypoints in the currently-selected track higher (searching inside the current track).
|
||||||
if (query.currentTrackId != -1 && waypoint.getTrackId() == query.currentTrackId) {
|
if (waypoint.getTrackId() != null && waypoint.getTrackId().equals(query.currentTrackId)) {
|
||||||
score *= CURRENT_TRACK_WAYPOINT_PROMOTION;
|
score *= CURRENT_TRACK_WAYPOINT_PROMOTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
@@ -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() + ", ") : "")
|
+ (waypoint != null ? ("wptId=" + waypoint.getId().getId() + ", ") : "")
|
||||||
+ "score=" + score + "]";
|
+ "score=" + score + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ 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;
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
@@ -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
|
||||||
@@ -311,7 +312,7 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
trackDataListener.clearWaypoints();
|
trackDataListener.clearWaypoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Cursor cursor = contentProviderUtils.getWaypointCursor(selectedTrackId, -1L, MAX_DISPLAYED_WAYPOINTS)) {
|
try (Cursor cursor = contentProviderUtils.getWaypointCursor(selectedTrackId, null, MAX_DISPLAYED_WAYPOINTS)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
do {
|
do {
|
||||||
Waypoint waypoint = contentProviderUtils.createWaypoint(cursor);
|
Waypoint waypoint = contentProviderUtils.createWaypoint(cursor);
|
||||||
@@ -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,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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,17 @@ 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.
|
* A waypoint.
|
||||||
*
|
*
|
||||||
@@ -30,12 +37,12 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
*/
|
*/
|
||||||
public final class Waypoint {
|
public final class Waypoint {
|
||||||
|
|
||||||
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;
|
||||||
@@ -51,7 +58,7 @@ public final class Waypoint {
|
|||||||
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 Waypoint(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 +70,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 +114,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 +158,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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+115
-69
@@ -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;
|
||||||
@@ -44,6 +48,7 @@ import de.dennisguse.opentracks.content.data.Waypoint;
|
|||||||
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,7 +94,7 @@ public class ContentProviderUtils {
|
|||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
public void clearTrack(long trackId) {
|
public void clearTrack(Track.Id trackId) {
|
||||||
deleteTrackPointsAndWaypoints(trackId);
|
deleteTrackPointsAndWaypoints(trackId);
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
track.setId(trackId);
|
track.setId(trackId);
|
||||||
@@ -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)));
|
||||||
@@ -184,14 +189,17 @@ 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) {
|
||||||
|
if (trackId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
deleteTrackPointsAndWaypoints(trackId);
|
deleteTrackPointsAndWaypoints(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())});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -199,15 +207,15 @@ public class ContentProviderUtils {
|
|||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
private void deleteTrackPointsAndWaypoints(long trackId) {
|
private void deleteTrackPointsAndWaypoints(@NonNull Track.Id trackId) {
|
||||||
String[] selectionArgs = new String[]{Long.toString(trackId)};
|
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
|
|
||||||
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(WaypointsColumns.CONTENT_URI, WaypointsColumns.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 +228,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 +252,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 +307,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 +315,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());
|
||||||
@@ -363,7 +382,7 @@ public class ContentProviderUtils {
|
|||||||
Waypoint waypoint = new Waypoint(location);
|
Waypoint waypoint = new Waypoint(location);
|
||||||
|
|
||||||
if (!cursor.isNull(idIndex)) {
|
if (!cursor.isNull(idIndex)) {
|
||||||
waypoint.setId(cursor.getLong(idIndex));
|
waypoint.setId(new Waypoint.Id(cursor.getLong(idIndex)));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(nameIndex)) {
|
if (!cursor.isNull(nameIndex)) {
|
||||||
waypoint.setName(cursor.getString(nameIndex));
|
waypoint.setName(cursor.getString(nameIndex));
|
||||||
@@ -378,7 +397,7 @@ public class ContentProviderUtils {
|
|||||||
waypoint.setIcon(cursor.getString(iconIndex));
|
waypoint.setIcon(cursor.getString(iconIndex));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(trackIdIndex)) {
|
if (!cursor.isNull(trackIdIndex)) {
|
||||||
waypoint.setTrackId(cursor.getLong(trackIdIndex));
|
waypoint.setTrackId(new Track.Id(cursor.getLong(trackIdIndex)));
|
||||||
}
|
}
|
||||||
if (!cursor.isNull(lengthIndex)) {
|
if (!cursor.isNull(lengthIndex)) {
|
||||||
waypoint.setLength(cursor.getFloat(lengthIndex));
|
waypoint.setLength(cursor.getFloat(lengthIndex));
|
||||||
@@ -393,10 +412,10 @@ public class ContentProviderUtils {
|
|||||||
return waypoint;
|
return waypoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteWaypoint(Context context, long waypointId) {
|
public void deleteWaypoint(Context context, Waypoint.Id waypointId) {
|
||||||
final Waypoint waypoint = getWaypoint(waypointId);
|
final Waypoint waypoint = getWaypoint(waypointId);
|
||||||
deleteWaypointPhoto(context, waypoint);
|
deleteWaypointPhoto(context, waypoint);
|
||||||
contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns._ID + "=?", new String[]{Long.toString(waypointId)});
|
contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns._ID + "=?", new String[]{Long.toString(waypointId.getId())});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -405,13 +424,13 @@ public class ContentProviderUtils {
|
|||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
* @return -1 if not able to get the next waypoint number.
|
* @return -1 if not able to get the next waypoint number.
|
||||||
*/
|
*/
|
||||||
public int getNextWaypointNumber(long trackId) {
|
public int getNextWaypointNumber(Track.Id trackId) {
|
||||||
if (trackId < 0) {
|
if (!trackId.isValid()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
String[] projection = {WaypointsColumns._ID};
|
String[] projection = {WaypointsColumns._ID};
|
||||||
String selection = WaypointsColumns.TRACKID + "=?";
|
String selection = WaypointsColumns.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 = getWaypointCursor(projection, selection, selectionArgs, WaypointsColumns._ID, -1)) {
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
return cursor.getCount();
|
return cursor.getCount();
|
||||||
@@ -420,12 +439,12 @@ public class ContentProviderUtils {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Waypoint getWaypoint(long waypointId) {
|
public Waypoint getWaypoint(Waypoint.Id waypointId) {
|
||||||
if (waypointId < 0) {
|
if (!waypointId.isValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try (Cursor cursor = getWaypointCursor(null, WaypointsColumns._ID + "=?",
|
try (Cursor cursor = getWaypointCursor(null, WaypointsColumns._ID + "=?",
|
||||||
new String[]{Long.toString(waypointId)}, WaypointsColumns._ID, 1)) {
|
new String[]{Long.toString(waypointId.getId())}, WaypointsColumns._ID, 1)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return createWaypoint(cursor);
|
return createWaypoint(cursor);
|
||||||
}
|
}
|
||||||
@@ -451,30 +470,30 @@ public class ContentProviderUtils {
|
|||||||
* 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 minWaypointId the minimum waypoint id. null to ignore
|
||||||
* @param maxWaypoints the maximum number of waypoints to return. -1 for no limit
|
* @param maxWaypoints the maximum number of waypoints to return. -1 for no limit
|
||||||
*/
|
*/
|
||||||
public Cursor getWaypointCursor(long trackId, long minWaypointId, int maxWaypoints) {
|
public Cursor getWaypointCursor(Track.Id trackId, @Nullable Waypoint.Id minWaypointId, int maxWaypoints) {
|
||||||
if (trackId < 0) {
|
if (!trackId.isValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String selection;
|
String selection;
|
||||||
String[] selectionArgs;
|
String[] selectionArgs;
|
||||||
if (minWaypointId >= 0) {
|
if (minWaypointId != null && minWaypointId.isValid()) {
|
||||||
selection = WaypointsColumns.TRACKID + "=? AND " + WaypointsColumns._ID + ">=?";
|
selection = WaypointsColumns.TRACKID + "=? AND " + WaypointsColumns._ID + ">=?";
|
||||||
selectionArgs = new String[]{Long.toString(trackId), Long.toString(minWaypointId)};
|
selectionArgs = new String[]{Long.toString(trackId.getId()), Long.toString(minWaypointId.getId())};
|
||||||
} else {
|
} else {
|
||||||
selection = WaypointsColumns.TRACKID + "=?";
|
selection = WaypointsColumns.TRACKID + "=?";
|
||||||
selectionArgs = new String[]{Long.toString(trackId)};
|
selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
}
|
}
|
||||||
return getWaypointCursor(null, selection, selectionArgs, WaypointsColumns._ID, maxWaypoints);
|
return getWaypointCursor(null, selection, selectionArgs, WaypointsColumns._ID, maxWaypoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public List<Waypoint> getWaypoints(long trackId) {
|
public List<Waypoint> getWaypoints(Track.Id trackId) {
|
||||||
ArrayList<Waypoint> waypoints = new ArrayList<>();
|
ArrayList<Waypoint> waypoints = new ArrayList<>();
|
||||||
try (Cursor cursor = getWaypointCursor(trackId, -1L, -1)) {
|
try (Cursor cursor = getWaypointCursor(trackId, null, -1)) {
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
do {
|
do {
|
||||||
waypoints.add(createWaypoint(cursor));
|
waypoints.add(createWaypoint(cursor));
|
||||||
@@ -484,19 +503,34 @@ public class ContentProviderUtils {
|
|||||||
return waypoints;
|
return waypoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Loader<Cursor> getWaypointsLoader(Context context, @Nullable Track.Id trackId) {
|
||||||
|
final String[] PROJECTION = new String[]{WaypointsColumns._ID,
|
||||||
|
WaypointsColumns.NAME, WaypointsColumns.DESCRIPTION, WaypointsColumns.CATEGORY,
|
||||||
|
WaypointsColumns.TIME, WaypointsColumns.PHOTOURL,
|
||||||
|
WaypointsColumns.LATITUDE, WaypointsColumns.LONGITUDE};
|
||||||
|
|
||||||
|
if (trackId != null) {
|
||||||
|
return new CursorLoader(context, WaypointsColumns.CONTENT_URI, PROJECTION,
|
||||||
|
WaypointsColumns.TRACKID + "=?",
|
||||||
|
new String[]{String.valueOf(trackId.getId())}, null);
|
||||||
|
} else {
|
||||||
|
return new CursorLoader(context, WaypointsColumns.CONTENT_URI, PROJECTION, null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of waypoints for a track.
|
* Gets the number of waypoints for a track.
|
||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
*/
|
*/
|
||||||
public int getWaypointCount(long trackId) {
|
public int getWaypointCount(Track.Id trackId) {
|
||||||
if (trackId < 0) {
|
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 = WaypointsColumns.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(WaypointsColumns.CONTENT_URI, projection, selection, selectionArgs, WaypointsColumns._ID)) {
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -512,8 +546,8 @@ public class ContentProviderUtils {
|
|||||||
* @param waypoint the waypoint
|
* @param waypoint the waypoint
|
||||||
* @return the content provider URI of the inserted waypoint.
|
* @return the content provider URI of the inserted waypoint.
|
||||||
*/
|
*/
|
||||||
public Uri insertWaypoint(Waypoint waypoint) {
|
public Uri insertWaypoint(@NonNull Waypoint waypoint) {
|
||||||
waypoint.setId(-1L);
|
waypoint.setId(null);
|
||||||
return contentResolver.insert(WaypointsColumns.CONTENT_URI, createContentValues(waypoint));
|
return contentResolver.insert(WaypointsColumns.CONTENT_URI, createContentValues(waypoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,22 +582,23 @@ public class ContentProviderUtils {
|
|||||||
if (!updatedWaypoint.hasPhoto()) {
|
if (!updatedWaypoint.hasPhoto()) {
|
||||||
deleteWaypointPhoto(context, savedWaypoint);
|
deleteWaypointPhoto(context, savedWaypoint);
|
||||||
}
|
}
|
||||||
int rows = contentResolver.update(WaypointsColumns.CONTENT_URI, createContentValues(updatedWaypoint), WaypointsColumns._ID + "=?", new String[]{Long.toString(updatedWaypoint.getId())});
|
int rows = contentResolver.update(WaypointsColumns.CONTENT_URI, createContentValues(updatedWaypoint), WaypointsColumns._ID + "=?", new String[]{Long.toString(updatedWaypoint.getId().getId())});
|
||||||
return rows == 1;
|
return rows == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentValues createContentValues(Waypoint waypoint) {
|
ContentValues createContentValues(@NonNull Waypoint waypoint) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
|
||||||
// Value < 0 indicates no id is available
|
if (waypoint.getId() != null && waypoint.getId().isValid()) {
|
||||||
if (waypoint.getId() >= 0) {
|
values.put(WaypointsColumns._ID, waypoint.getId().getId());
|
||||||
values.put(WaypointsColumns._ID, waypoint.getId());
|
|
||||||
}
|
}
|
||||||
values.put(WaypointsColumns.NAME, waypoint.getName());
|
values.put(WaypointsColumns.NAME, waypoint.getName());
|
||||||
values.put(WaypointsColumns.DESCRIPTION, waypoint.getDescription());
|
values.put(WaypointsColumns.DESCRIPTION, waypoint.getDescription());
|
||||||
values.put(WaypointsColumns.CATEGORY, waypoint.getCategory());
|
values.put(WaypointsColumns.CATEGORY, waypoint.getCategory());
|
||||||
values.put(WaypointsColumns.ICON, waypoint.getIcon());
|
values.put(WaypointsColumns.ICON, waypoint.getIcon());
|
||||||
values.put(WaypointsColumns.TRACKID, waypoint.getTrackId());
|
if (waypoint.getTrackId() != null) {
|
||||||
|
values.put(WaypointsColumns.TRACKID, waypoint.getTrackId().getId());
|
||||||
|
}
|
||||||
values.put(WaypointsColumns.LENGTH, waypoint.getLength());
|
values.put(WaypointsColumns.LENGTH, waypoint.getLength());
|
||||||
values.put(WaypointsColumns.DURATION, waypoint.getDuration());
|
values.put(WaypointsColumns.DURATION, waypoint.getDuration());
|
||||||
|
|
||||||
@@ -656,7 +691,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 +701,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 +727,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 +749,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 +780,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 +790,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 +813,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,7 +829,7 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,9 +839,9 @@ public class ContentProviderUtils {
|
|||||||
* @param trackPoint the trackPoint
|
* @param trackPoint the trackPoint
|
||||||
* @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 +882,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 +908,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 +939,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) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
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.data.WaypointsColumns;
|
||||||
@@ -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());
|
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(tracks, 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;
|
||||||
|
|||||||
@@ -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.Waypoint;
|
||||||
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, Waypoint.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,23 +64,23 @@ 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 Waypoint.Id[] waypointIds = (Waypoint.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 (waypointIds == 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 {
|
||||||
titleId = markerIds.length > 1 ? R.string.generic_delete_selected_confirm_title : R.string.marker_delete_one_confirm_title;
|
titleId = waypointIds.length > 1 ? R.string.generic_delete_selected_confirm_title : R.string.marker_delete_one_confirm_title;
|
||||||
messageId = markerIds.length > 1 ? R.string.marker_delete_multiple_confirm_message : R.string.marker_delete_one_confirm_message;
|
messageId = waypointIds.length > 1 ? R.string.marker_delete_multiple_confirm_message : R.string.marker_delete_one_confirm_message;
|
||||||
}
|
}
|
||||||
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 (Waypoint.Id waypointId : waypointIds) {
|
||||||
contentProviderUtils.deleteWaypoint(getContext(), markerId);
|
contentProviderUtils.deleteWaypoint(getContext(), waypointId);
|
||||||
}
|
}
|
||||||
caller.onDeleteMarkerDone();
|
caller.onDeleteMarkerDone();
|
||||||
}).start());
|
}).start());
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ public class ExportProgressDialogFragment extends DialogFragment {
|
|||||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -93,9 +93,9 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static MarkerDetailFragment newInstance(long markerId) {
|
public static MarkerDetailFragment newInstance(Waypoint.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);
|
Waypoint.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);
|
Waypoint.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.getWaypoint(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();
|
||||||
|
|||||||
@@ -76,7 +76,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());
|
||||||
|
|||||||
@@ -98,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.getWaypointCursor(track.getId(), null, ContentProviderUtils.MAX_LOADED_WAYPOINTS_POINTS)) {
|
||||||
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()) {
|
||||||
|
|||||||
@@ -388,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();
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public class KmzTrackExporter implements TrackExporter {
|
|||||||
|
|
||||||
private void addImages(Context context, Track[] tracks, 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.getWaypointCursor(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()) {
|
||||||
|
|||||||
+11
-11
@@ -68,8 +68,8 @@ 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<Waypoint> waypoints = new ArrayList<>();
|
||||||
|
|
||||||
// The current element content
|
// The current element content
|
||||||
@@ -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,7 +153,7 @@ 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;
|
||||||
@@ -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));
|
||||||
@@ -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,6 +32,7 @@ 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.Track;
|
||||||
import de.dennisguse.opentracks.content.data.Waypoint;
|
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.exporter.KmzTrackExporter;
|
import de.dennisguse.opentracks.io.file.exporter.KmzTrackExporter;
|
||||||
@@ -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,8 +196,8 @@ 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<Waypoint> waypoints = contentProviderUtils.getWaypoints(trackId);
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,9 +230,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
*
|
*
|
||||||
* @return the waypoint id
|
* @return the waypoint id
|
||||||
*/
|
*/
|
||||||
public long insertWaypoint(String name, String category, String description, String photoUrl) {
|
public Waypoint.Id 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) {
|
||||||
@@ -246,7 +246,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
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 waypoint as trackPoint is unknown.");
|
||||||
return -1L;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
category = category != null ? category : "";
|
category = category != null ? category : "";
|
||||||
@@ -261,7 +261,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
// Insert waypoint
|
// Insert waypoint
|
||||||
Waypoint waypoint = new Waypoint(name, description, category, icon, recordingTrackId, length, duration, trackPoint.getLocation(), photoUrl);
|
Waypoint waypoint = new Waypoint(name, description, category, icon, recordingTrackId, length, duration, trackPoint.getLocation(), photoUrl);
|
||||||
Uri uri = contentProviderUtils.insertWaypoint(waypoint);
|
Uri uri = contentProviderUtils.insertWaypoint(waypoint);
|
||||||
return ContentUris.parseId(uri);
|
return new Waypoint.Id(ContentUris.parseId(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -269,10 +269,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 +280,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 +305,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 +333,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 +403,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 +489,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 +507,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,7 +2,9 @@ package de.dennisguse.opentracks.services;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
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.SensorDataSet;
|
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||||
@@ -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,7 +90,7 @@ class TrackRecordingServiceBinder extends android.os.Binder implements TrackReco
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long insertWaypoint(String name, String category, String description, String photoUrl) {
|
public Waypoint.Id insertWaypoint(String name, String category, String description, String photoUrl) {
|
||||||
return trackRecordingService.insertWaypoint(name, category, description, photoUrl);
|
return trackRecordingService.insertWaypoint(name, category, description, photoUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-7
@@ -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.Track;
|
||||||
|
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||||
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 Waypoint.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);
|
Waypoint.Id waypoint = trackRecordingService.insertWaypoint(name, category, description, photoUrl);
|
||||||
if (markerId != -1L) {
|
if (waypoint != 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 waypoint;
|
||||||
}
|
}
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
Log.e(TAG, "Unable to add marker.", e);
|
Log.e(TAG, "Unable to add marker.", e);
|
||||||
@@ -196,7 +198,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -213,7 +215,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)
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ package de.dennisguse.opentracks.services;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
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.SensorDataSet;
|
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||||
@@ -43,12 +45,12 @@ public interface TrackRecordingServiceInterface {
|
|||||||
*
|
*
|
||||||
* @return the track ID of the new track.
|
* @return the track ID of the new track.
|
||||||
*/
|
*/
|
||||||
long startNewTrack();
|
Track.Id startNewTrack();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resumes the track identified by trackId.
|
* Resumes the track identified by trackId.
|
||||||
*/
|
*/
|
||||||
void resumeTrack(long trackId);
|
void resumeTrack(Track.Id trackId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses the current recording track.
|
* Pauses the current recording track.
|
||||||
@@ -76,13 +78,14 @@ 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();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,7 +93,7 @@ public interface TrackRecordingServiceInterface {
|
|||||||
*
|
*
|
||||||
* @return the ID of the inserted waypoint
|
* @return the ID of the inserted waypoint
|
||||||
*/
|
*/
|
||||||
long insertWaypoint(String name, String category, String description, String photoUrl);
|
Waypoint.Id 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.
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class GpsStatus {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method must be called from the client every time a new location is received.
|
* This method must be called from the client every time a new location is received.
|
||||||
* Receive new location and calculatsrc/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java the new status if needed.
|
* Receive new location and calculate the new status if needed.
|
||||||
* 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) {
|
||||||
|
|||||||
@@ -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,7 +8,10 @@ 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.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.data.WaypointsColumns;
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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());
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,9 +55,9 @@ public class PreferencesUtils {
|
|||||||
public static final long RECORDING_TRACK_ID_DEFAULT = -1L;
|
public static final long RECORDING_TRACK_ID_DEFAULT = -1L;
|
||||||
|
|
||||||
@Deprecated //Use the TrackRecordingService
|
@Deprecated //Use the TrackRecordingService
|
||||||
public static long getRecordingTrackId(Context context) {
|
public static Track.Id getRecordingTrackId(Context context) {
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
||||||
return sharedPreferences.getLong(getKey(context, R.string.recording_track_id_key), RECORDING_TRACK_ID_DEFAULT);
|
return new Track.Id(sharedPreferences.getLong(getKey(context, R.string.recording_track_id_key), RECORDING_TRACK_ID_DEFAULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDefaultActivity(Context context) {
|
public static String getDefaultActivity(Context context) {
|
||||||
@@ -347,14 +348,16 @@ public class PreferencesUtils {
|
|||||||
|
|
||||||
@Deprecated //Use TrackRecordingService
|
@Deprecated //Use TrackRecordingService
|
||||||
public static boolean isRecording(Context context) {
|
public static boolean isRecording(Context context) {
|
||||||
long recordingTrackId = getRecordingTrackId(context);
|
return isRecording(getRecordingTrackId(context));
|
||||||
return isRecording(recordingTrackId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
//TODO Method is very misleading: it only checks if the provided trackId not the default value (i.e., not recording).
|
//TODO Method is very misleading: it only checks if the provided trackId not the default value (i.e., not recording).
|
||||||
public static boolean isRecording(long recordingTrackId) {
|
public static boolean isRecording(Track.Id recordingTrackId) {
|
||||||
return recordingTrackId != RECORDING_TRACK_ID_DEFAULT;
|
if (recordingTrackId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return recordingTrackId.getId() != RECORDING_TRACK_ID_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void resetPreferences(Context context, boolean readAgain) {
|
public static void resetPreferences(Context context, boolean readAgain) {
|
||||||
|
|||||||
@@ -17,26 +17,19 @@ package de.dennisguse.opentracks.util;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Build;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.ParsePosition;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
|
||||||
@@ -52,23 +45,6 @@ public class StringUtils {
|
|||||||
|
|
||||||
private static final String COORDINATE_DEGREE = "\u00B0";
|
private static final String COORDINATE_DEGREE = "\u00B0";
|
||||||
|
|
||||||
//TODO Remove when upgrading to API level 26+.
|
|
||||||
@Deprecated
|
|
||||||
private static final SimpleDateFormat ISO_8601_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
|
|
||||||
|
|
||||||
//TODO Remove when upgrading to API level 26+.
|
|
||||||
@Deprecated
|
|
||||||
private static final SimpleDateFormat ISO_8601_BASE = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
|
|
||||||
|
|
||||||
//TODO Remove when upgrading to API level 26+.
|
|
||||||
@Deprecated
|
|
||||||
private static final Pattern ISO_8601_EXTRAS = Pattern.compile("^(\\.\\d+)?(?:Z|([+-])(\\d{2}):(\\d{2}))?$");
|
|
||||||
|
|
||||||
static {
|
|
||||||
ISO_8601_DATE_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
||||||
ISO_8601_BASE.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringUtils() {
|
private StringUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,17 +60,12 @@ public class StringUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the time using the ISO 8601 date time_ms format with fractional
|
* Formats the time using the ISO 8601 date time_ms format with fractional seconds in UTC time zone.
|
||||||
* seconds in UTC time zone.
|
|
||||||
*
|
*
|
||||||
* @param time_ms the time in milliseconds
|
* @param time_ms the time in milliseconds
|
||||||
*/
|
*/
|
||||||
public static String formatDateTimeIso8601(long time_ms) {
|
public static String formatDateTimeIso8601(long time_ms) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
return Instant.ofEpochMilli(time_ms).toString();
|
||||||
return Instant.ofEpochMilli(time_ms).toString();
|
|
||||||
} else {
|
|
||||||
return ISO_8601_DATE_TIME_FORMAT.format(time_ms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -292,72 +263,17 @@ public class StringUtils {
|
|||||||
* @param xmlDateTime the XML date time string
|
* @param xmlDateTime the XML date time string
|
||||||
*/
|
*/
|
||||||
public static long parseTime(String xmlDateTime) {
|
public static long parseTime(String xmlDateTime) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
try {
|
||||||
try {
|
TemporalAccessor t = DateTimeFormatter.ISO_DATE_TIME.parseBest(xmlDateTime, ZonedDateTime::from, LocalDateTime::from);
|
||||||
TemporalAccessor t = DateTimeFormatter.ISO_DATE_TIME.parseBest(xmlDateTime, ZonedDateTime::from, LocalDateTime::from);
|
if (t instanceof LocalDateTime) {
|
||||||
if (t instanceof LocalDateTime) {
|
Log.w(TAG, "Date does not contain timezone information: using UTC.");
|
||||||
Log.w(TAG, "Date does not contain timezone information: using UTC.");
|
t = ((LocalDateTime) t).atZone(ZoneOffset.UTC);
|
||||||
t = ((LocalDateTime) t).atZone(ZoneOffset.UTC);
|
|
||||||
}
|
|
||||||
return Instant.from(t).toEpochMilli();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Invalid XML dateTime value");
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
return Instant.from(t).toEpochMilli();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Invalid XML dateTime value");
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO Remove the following when upgrading to API level 26+.
|
|
||||||
|
|
||||||
// Parse the date time base
|
|
||||||
ParsePosition position = new ParsePosition(0);
|
|
||||||
Date date = ISO_8601_BASE.parse(xmlDateTime, position);
|
|
||||||
if (date == null) {
|
|
||||||
throw new IllegalArgumentException("Invalid XML dateTime value: " + xmlDateTime + " (at position " + position.getErrorIndex() + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the date time extras
|
|
||||||
Matcher matcher = ISO_8601_EXTRAS.matcher(xmlDateTime.substring(position.getIndex()));
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
// This will match even an empty string as all groups are optional. Thus a non-match means invalid content.
|
|
||||||
throw new IllegalArgumentException("Invalid XML dateTime value: " + xmlDateTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
long time = date.getTime();
|
|
||||||
|
|
||||||
// Account for fractional seconds
|
|
||||||
String fractional = matcher.group(1);
|
|
||||||
if (fractional != null) {
|
|
||||||
// Regex ensures fractional part is in (0,1)
|
|
||||||
float fractionalSeconds = Float.parseFloat(fractional);
|
|
||||||
long fractionalMillis = Math.round(fractionalSeconds * UnitConversions.S_TO_MS);
|
|
||||||
time += fractionalMillis;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account for timezones
|
|
||||||
String sign = matcher.group(2);
|
|
||||||
String offsetHoursStr = matcher.group(3);
|
|
||||||
String offsetMinsStr = matcher.group(4);
|
|
||||||
if (sign != null && offsetHoursStr != null && offsetMinsStr != null) {
|
|
||||||
// Regex ensures sign is + or -
|
|
||||||
boolean plusSign = sign.equals("+");
|
|
||||||
int offsetHours = Integer.parseInt(offsetHoursStr);
|
|
||||||
int offsetMins = Integer.parseInt(offsetMinsStr);
|
|
||||||
|
|
||||||
// Regex ensures values are >= 0
|
|
||||||
if (offsetHours > 14 || offsetMins > 59) {
|
|
||||||
throw new IllegalArgumentException("Bad timezone: " + xmlDateTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
long totalOffsetMillis = (offsetMins + offsetHours * 60L) * 60000L;
|
|
||||||
|
|
||||||
// Convert to UTC
|
|
||||||
if (plusSign) {
|
|
||||||
time -= totalOffsetMillis;
|
|
||||||
} else {
|
|
||||||
time += totalOffsetMillis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.text.SimpleDateFormat;
|
|||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for track name.
|
* Utilities for track name.
|
||||||
@@ -46,7 +47,7 @@ public class TrackNameUtils {
|
|||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
* @param startTime the track start time
|
* @param startTime the track start time
|
||||||
*/
|
*/
|
||||||
public static String getTrackName(Context context, long trackId, long startTime) {
|
public static String getTrackName(Context context, Track.Id trackId, long startTime) {
|
||||||
String trackName = PreferencesUtils.getString(context, R.string.track_name_key, context.getString(R.string.track_name_default));
|
String trackName = PreferencesUtils.getString(context, R.string.track_name_key, context.getString(R.string.track_name_default));
|
||||||
|
|
||||||
if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_local_value))) {
|
if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_local_value))) {
|
||||||
@@ -54,7 +55,7 @@ public class TrackNameUtils {
|
|||||||
} else if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_iso_8601_value))) {
|
} else if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_iso_8601_value))) {
|
||||||
return new SimpleDateFormat(ISO_8601_FORMAT, Locale.US).format(startTime);
|
return new SimpleDateFormat(ISO_8601_FORMAT, Locale.US).format(startTime);
|
||||||
} else {
|
} else {
|
||||||
return context.getString(R.string.track_name_format, trackId);
|
return context.getString(R.string.track_name_format, trackId.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class AggregatedStatisticsModel extends AndroidViewModel {
|
|||||||
private void loadAggregatedStats() {
|
private void loadAggregatedStats() {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(getApplication().getApplicationContext());
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(getApplication().getApplicationContext());
|
||||||
List<Track> tracks = contentProviderUtils.getAllTracks();
|
List<Track> tracks = contentProviderUtils.getTracks();
|
||||||
|
|
||||||
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
|
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
|
||||||
aggregatedStatistics.aggregate(tracks);
|
aggregatedStatistics.aggregate(tracks);
|
||||||
|
|||||||
@@ -1,5 +1,40 @@
|
|||||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:drawable="@drawable/ic_button_stop" >
|
xmlns:aapt="http://schemas.android.com/aapt">
|
||||||
|
<aapt:attr name="android:drawable">
|
||||||
|
<vector
|
||||||
|
android:width="82dp"
|
||||||
|
android:height="82dp"
|
||||||
|
android:viewportWidth="125"
|
||||||
|
android:viewportHeight="125">
|
||||||
|
<path
|
||||||
|
android:fillAlpha="1"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M2.516,63.008a60.239,59.73 134.879,1 0,119.968 -1.017a60.239,59.73 134.879,1 0,-119.968 1.017z"
|
||||||
|
android:strokeWidth="5.03194237"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeColor="#555555" />
|
||||||
|
<path
|
||||||
|
android:fillAlpha="1"
|
||||||
|
android:fillColor="#484848"
|
||||||
|
android:pathData="M62.5,62.5m-50,0a50,50 0,1 1,100 0a50,50 0,1 1,-100 0"
|
||||||
|
android:strokeWidth="6.9172821"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
<path
|
||||||
|
android:fillAlpha="1"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M53.02,54.02h17.46v17.46h-17.46z"
|
||||||
|
android:strokeWidth="1.04023623"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeColor="#414141" />
|
||||||
|
<path android:name="fade_out_circle"
|
||||||
|
android:pathData="M62.5,62.5m-0,-62a50,50 0,1 1,-0 123a50,50 0,1 1,-0 -123"
|
||||||
|
android:fillAlpha="0.0"
|
||||||
|
android:fillColor="#a31a1f">
|
||||||
|
</path>
|
||||||
|
</vector>
|
||||||
|
</aapt:attr>
|
||||||
<target
|
<target
|
||||||
android:name="fade_out_circle"
|
android:name="fade_out_circle"
|
||||||
android:animation="@animator/button_animator" />
|
android:animation="@animator/button_animator" />
|
||||||
|
|||||||
Reference in New Issue
Block a user