diff --git a/src/androidTest/java/de/dennisguse/opentracks/util/ExportUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/util/ExportUtilsTest.java new file mode 100644 index 000000000..7e9de362c --- /dev/null +++ b/src/androidTest/java/de/dennisguse/opentracks/util/ExportUtilsTest.java @@ -0,0 +1,60 @@ +package de.dennisguse.opentracks.util; + +import junit.framework.TestCase; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class ExportUtilsTest extends TestCase { + + @Test + public void testIsExportFileExists_exists() { + // given + UUID uuid = UUID.randomUUID(); + String format = "kmz"; + List fileNames = new ArrayList<>(); + fileNames.add(uuid.toString().substring(0, 8) + "_name.gpx"); + fileNames.add(uuid.toString().substring(0, 8) + "_other name name.kmz"); + + // when + boolean exists = ExportUtils.isExportFileExists(uuid, format, fileNames); + + // then + assertTrue(exists); + } + + @Test + public void testIsExportFileExists_not_exists1() { + // given + UUID uuid = UUID.randomUUID(); + String format = "gpx"; + List fileNames = new ArrayList<>(); + fileNames.add(UUID.randomUUID().toString().substring(0, 8) + "_name.gpx"); + fileNames.add(UUID.randomUUID().toString().substring(0, 8) + "_other name name.gpx"); + + // when + boolean exists = ExportUtils.isExportFileExists(uuid, format, fileNames); + + // then + assertFalse(exists); + } + + @Test + public void testIsExportFileExists_not_exists2() { + // given + UUID uuid = UUID.randomUUID(); + String format = "kmz"; + List fileNames = new ArrayList<>(); + fileNames.add(uuid.toString().substring(0, 8) + "_name.gpx"); + fileNames.add(UUID.randomUUID().toString().substring(0, 8) + "_other name name.gpx"); + + // when + boolean exists = ExportUtils.isExportFileExists(uuid, format, fileNames); + + // then + assertFalse(exists); + } +} diff --git a/src/main/java/de/dennisguse/opentracks/content/data/Track.java b/src/main/java/de/dennisguse/opentracks/content/data/Track.java index 194e98806..1d0304dba 100644 --- a/src/main/java/de/dennisguse/opentracks/content/data/Track.java +++ b/src/main/java/de/dennisguse/opentracks/content/data/Track.java @@ -109,6 +109,19 @@ public class Track { this.trackStatistics = trackStatistics; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Track track = (Track) o; + return id.equals(track.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + public static class Id implements Parcelable { private final long id; diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/ExportActivity.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/ExportActivity.java index f31dafe18..95b112533 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/ExportActivity.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/ExportActivity.java @@ -91,7 +91,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes private ContentProviderUtils contentProviderUtils; // List of tracks to be exported. - private final ArrayList trackIds = new ArrayList<>(); + private final ArrayList tracks = new ArrayList<>(); private final LinkedBlockingQueue conflictsQueue = new LinkedBlockingQueue<>(); private final Handler conflictsHandler = new Handler(); @@ -187,7 +187,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes protected void onDestroy() { super.onDestroy(); conflictsQueue.clear(); - trackIds.clear(); + tracks.clear(); } @Override @@ -215,11 +215,11 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes for (int i = from; i < trackExportTotalCount; i++) { cursor.moveToPosition(i); Track track = ContentProviderUtils.createTrack(cursor); - trackIds.add(track.getId()); + tracks.add(track); } - if (!trackIds.isEmpty()) { - export(trackIds.get(0)); + if (!tracks.isEmpty()) { + export(tracks.get(0)); } else { onExportEnded(); } @@ -227,26 +227,26 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes } /** - * Enqueue track identified by trackId to be exported if not exported already or there is a conflict resolution. + * Enqueue track identified by UUID to be exported if not exported already or there is a conflict resolution. * - * @param trackId the track's id. + * @param track Track object. * @param conflictResolution conflict resolution to be applied if needed. */ - private void export(Track.Id trackId, int conflictResolution) { - boolean fileExists = ExportUtils.isExportFileExists(trackId, trackFileFormat.getExtension(), directoryFiles); + private void export(Track track, int conflictResolution) { + boolean fileExists = ExportUtils.isExportFileExists(track.getUuid(), trackFileFormat.getExtension(), directoryFiles); if (fileExists && conflictResolution == CONFLICT_NONE) { - conflict(trackId); + conflict(track); } else if (fileExists && conflictResolution == CONFLICT_SKIP) { trackExportSkippedCount++; - onExportCompleted(trackId); + onExportCompleted(track); } else { - ExportService.enqueue(this, resultReceiver, trackId, trackFileFormat, directoryUri); + ExportService.enqueue(this, resultReceiver, track.getId(), trackFileFormat, directoryUri); } } - private void export(Track.Id trackId) { - export(trackId, autoConflict); + private void export(Track track) { + export(track, autoConflict); } private void setConflictVisibility(int visibility) { @@ -278,14 +278,15 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes viewBinding.exportProgressSummaryErrorsGroup.setVisibility(trackExportErrorCount > 0 ? View.VISIBLE : View.GONE); } - private void onExportCompleted(Track.Id trackId) { - trackIds.remove(trackId); + private void onExportCompleted(Track track) { + tracks.remove(track); + setProgress(); - if (trackIds.isEmpty()) { + if (tracks.isEmpty()) { onExportEnded(); return; } - export(trackIds.get(0)); + export(tracks.get(0)); } private void onExportEnded() { @@ -317,15 +318,15 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes } Track.Id trackId = resultData.getParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID); + Track track = contentProviderUtils.getTrack(trackId); switch (resultCode) { case ExportServiceResultReceiver.RESULT_CODE_ERROR: trackExportErrorCount++; - Track track = contentProviderUtils.getTrack(trackId); trackErrors.add(track.getName()); break; case ExportServiceResultReceiver.RESULT_CODE_SUCCESS: - if (ExportUtils.isExportFileExists(trackId, trackFileFormat.getExtension(), directoryFiles)) { + if (ExportUtils.isExportFileExists(track.getUuid(), trackFileFormat.getExtension(), directoryFiles)) { trackExportOverwrittenCount++; } else { trackExportSuccessCount++; @@ -335,11 +336,11 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes throw new RuntimeException(TAG + ": export service result code invalid: " + resultCode); } - onExportCompleted(trackId); + onExportCompleted(track); } - private void conflict(Track.Id trackId) { - PendingConflict newConflict = new PendingConflict(trackId); + private void conflict(Track track) { + PendingConflict newConflict = new PendingConflict(track); conflictsQueue.add(newConflict); if (conflictsQueue.size() == 1) { @@ -351,10 +352,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes * Handle conflicts (exporting file already exists). */ private class PendingConflict { - private final Track.Id trackId; + private final Track track; - public PendingConflict(Track.Id trackId) { - this.trackId = trackId; + public PendingConflict(Track track) { + this.track = track; } /** @@ -365,14 +366,13 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes */ public boolean resolve() { if (autoConflict == CONFLICT_NONE) { - Track track = contentProviderUtils.getTrack(trackId); viewBinding.exportProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(ExportActivity.this, R.drawable.ic_report_problem_24)); viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, track.getName())); setConflictVisibility(View.VISIBLE); return false; } - export(trackId); + export(track); return true; } @@ -380,7 +380,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes * Overwrite the export file and set the autoConflict if user set the "do it for all" switch button. */ public void overwrite() { - export(trackId, CONFLICT_OVERWRITE); + export(track, CONFLICT_OVERWRITE); if (viewBinding.exportProgressApplyToAll.isChecked()) { autoConflict = CONFLICT_OVERWRITE; @@ -391,7 +391,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes * Skip the export file and set the autoConflict if user set the "do it for all" switch button. */ public void skip() { - export(trackId, CONFLICT_SKIP); + export(track, CONFLICT_SKIP); if (viewBinding.exportProgressApplyToAll.isChecked()) { autoConflict = CONFLICT_SKIP; diff --git a/src/main/java/de/dennisguse/opentracks/util/ExportUtils.java b/src/main/java/de/dennisguse/opentracks/util/ExportUtils.java index 0d9a76576..3efbed1ae 100644 --- a/src/main/java/de/dennisguse/opentracks/util/ExportUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/ExportUtils.java @@ -14,6 +14,8 @@ import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import java.util.UUID; +import java.util.regex.Pattern; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.io.file.TrackFileFormat; @@ -37,7 +39,7 @@ public class ExportUtils { public static boolean exportTrack(Context context, TrackFileFormat trackFileFormat, DocumentFile directory, Track track) { TrackExporter trackExporter = trackFileFormat.createTrackExporter(context); - Uri exportDocumentFileUri = getExportDocumentFileUri(context, track.getId(), trackFileFormat, directory); + Uri exportDocumentFileUri = getExportDocumentFileUri(context, track, trackFileFormat, directory); if (exportDocumentFileUri == null) { Log.e(TAG, "Couldn't create document file for export"); return false; @@ -62,8 +64,10 @@ public class ExportUtils { } } - public static boolean isExportFileExists(Track.Id trackId, String trackFileFormatExtension, List filesName) { - return filesName.contains(getExportFileNameByTrackId(trackId, trackFileFormatExtension)); + public static boolean isExportFileExists(UUID uuuid, String trackFileFormatExtension, List filesName) { + String word = uuuid.toString().substring(0, 8) + ".*\\." + trackFileFormatExtension; + Pattern pattern = Pattern.compile(word); + return filesName.stream().anyMatch(w -> pattern.matcher(w).matches()); } public static List getAllFiles(Context context, Uri directoryUri) { @@ -82,8 +86,8 @@ public class ExportUtils { return fileNames; } - private static Uri getExportDocumentFileUri(Context context, Track.Id trackId, TrackFileFormat trackFileFormat, DocumentFile directory) { - String exportFileName = getExportFileNameByTrackId(trackId, trackFileFormat.getExtension()); + private static Uri getExportDocumentFileUri(Context context, Track track, TrackFileFormat trackFileFormat, DocumentFile directory) { + String exportFileName = getExportFileNameForTrack(track, trackFileFormat.getExtension()); Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName); if (exportDocumentFileUri == null) { final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName); @@ -94,8 +98,8 @@ public class ExportUtils { return exportDocumentFileUri; } - private static String getExportFileNameByTrackId(Track.Id trackId, String trackFileFormatExtension) { - return trackId.getId() + "." + trackFileFormatExtension; + private static String getExportFileNameForTrack(Track track, String trackFileFormatExtension) { + return track.getUuid().toString().substring(0, 8) + "_" + track.getName() + "." + trackFileFormatExtension; } private static Uri findFile(Context context, Uri directoryUri, String exportFileName) {