Track exported names: UUID, track's name and extension
This commit is contained in:
Román Martínez
2021-03-14 18:43:28 +01:00
committed by GitHub
4 changed files with 114 additions and 37 deletions
@@ -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<String> 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<String> 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<String> 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);
}
}
@@ -109,6 +109,19 @@ public class Track {
this.trackStatistics = trackStatistics; 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 { public static class Id implements Parcelable {
private final long id; private final long id;
@@ -91,7 +91,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
private ContentProviderUtils contentProviderUtils; private ContentProviderUtils contentProviderUtils;
// List of tracks to be exported. // List of tracks to be exported.
private final ArrayList<Track.Id> trackIds = new ArrayList<>(); private final ArrayList<Track> tracks = new ArrayList<>();
private final LinkedBlockingQueue<PendingConflict> conflictsQueue = new LinkedBlockingQueue<>(); private final LinkedBlockingQueue<PendingConflict> conflictsQueue = new LinkedBlockingQueue<>();
private final Handler conflictsHandler = new Handler(); private final Handler conflictsHandler = new Handler();
@@ -187,7 +187,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
conflictsQueue.clear(); conflictsQueue.clear();
trackIds.clear(); tracks.clear();
} }
@Override @Override
@@ -215,11 +215,11 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
for (int i = from; i < trackExportTotalCount; i++) { for (int i = from; i < trackExportTotalCount; i++) {
cursor.moveToPosition(i); cursor.moveToPosition(i);
Track track = ContentProviderUtils.createTrack(cursor); Track track = ContentProviderUtils.createTrack(cursor);
trackIds.add(track.getId()); tracks.add(track);
} }
if (!trackIds.isEmpty()) { if (!tracks.isEmpty()) {
export(trackIds.get(0)); export(tracks.get(0));
} else { } else {
onExportEnded(); 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. * @param conflictResolution conflict resolution to be applied if needed.
*/ */
private void export(Track.Id trackId, int conflictResolution) { private void export(Track track, int conflictResolution) {
boolean fileExists = ExportUtils.isExportFileExists(trackId, trackFileFormat.getExtension(), directoryFiles); boolean fileExists = ExportUtils.isExportFileExists(track.getUuid(), trackFileFormat.getExtension(), directoryFiles);
if (fileExists && conflictResolution == CONFLICT_NONE) { if (fileExists && conflictResolution == CONFLICT_NONE) {
conflict(trackId); conflict(track);
} else if (fileExists && conflictResolution == CONFLICT_SKIP) { } else if (fileExists && conflictResolution == CONFLICT_SKIP) {
trackExportSkippedCount++; trackExportSkippedCount++;
onExportCompleted(trackId); onExportCompleted(track);
} else { } else {
ExportService.enqueue(this, resultReceiver, trackId, trackFileFormat, directoryUri); ExportService.enqueue(this, resultReceiver, track.getId(), trackFileFormat, directoryUri);
} }
} }
private void export(Track.Id trackId) { private void export(Track track) {
export(trackId, autoConflict); export(track, autoConflict);
} }
private void setConflictVisibility(int visibility) { 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); viewBinding.exportProgressSummaryErrorsGroup.setVisibility(trackExportErrorCount > 0 ? View.VISIBLE : View.GONE);
} }
private void onExportCompleted(Track.Id trackId) { private void onExportCompleted(Track track) {
trackIds.remove(trackId); tracks.remove(track);
setProgress(); setProgress();
if (trackIds.isEmpty()) { if (tracks.isEmpty()) {
onExportEnded(); onExportEnded();
return; return;
} }
export(trackIds.get(0)); export(tracks.get(0));
} }
private void onExportEnded() { 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.Id trackId = resultData.getParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID);
Track track = contentProviderUtils.getTrack(trackId);
switch (resultCode) { switch (resultCode) {
case ExportServiceResultReceiver.RESULT_CODE_ERROR: case ExportServiceResultReceiver.RESULT_CODE_ERROR:
trackExportErrorCount++; trackExportErrorCount++;
Track track = contentProviderUtils.getTrack(trackId);
trackErrors.add(track.getName()); trackErrors.add(track.getName());
break; break;
case ExportServiceResultReceiver.RESULT_CODE_SUCCESS: case ExportServiceResultReceiver.RESULT_CODE_SUCCESS:
if (ExportUtils.isExportFileExists(trackId, trackFileFormat.getExtension(), directoryFiles)) { if (ExportUtils.isExportFileExists(track.getUuid(), trackFileFormat.getExtension(), directoryFiles)) {
trackExportOverwrittenCount++; trackExportOverwrittenCount++;
} else { } else {
trackExportSuccessCount++; trackExportSuccessCount++;
@@ -335,11 +336,11 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
throw new RuntimeException(TAG + ": export service result code invalid: " + resultCode); throw new RuntimeException(TAG + ": export service result code invalid: " + resultCode);
} }
onExportCompleted(trackId); onExportCompleted(track);
} }
private void conflict(Track.Id trackId) { private void conflict(Track track) {
PendingConflict newConflict = new PendingConflict(trackId); PendingConflict newConflict = new PendingConflict(track);
conflictsQueue.add(newConflict); conflictsQueue.add(newConflict);
if (conflictsQueue.size() == 1) { if (conflictsQueue.size() == 1) {
@@ -351,10 +352,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
* Handle conflicts (exporting file already exists). * Handle conflicts (exporting file already exists).
*/ */
private class PendingConflict { private class PendingConflict {
private final Track.Id trackId; private final Track track;
public PendingConflict(Track.Id trackId) { public PendingConflict(Track track) {
this.trackId = trackId; this.track = track;
} }
/** /**
@@ -365,14 +366,13 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
*/ */
public boolean resolve() { public boolean resolve() {
if (autoConflict == CONFLICT_NONE) { if (autoConflict == CONFLICT_NONE) {
Track track = contentProviderUtils.getTrack(trackId);
viewBinding.exportProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(ExportActivity.this, R.drawable.ic_report_problem_24)); 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())); viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, track.getName()));
setConflictVisibility(View.VISIBLE); setConflictVisibility(View.VISIBLE);
return false; return false;
} }
export(trackId); export(track);
return true; 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. * Overwrite the export file and set the autoConflict if user set the "do it for all" switch button.
*/ */
public void overwrite() { public void overwrite() {
export(trackId, CONFLICT_OVERWRITE); export(track, CONFLICT_OVERWRITE);
if (viewBinding.exportProgressApplyToAll.isChecked()) { if (viewBinding.exportProgressApplyToAll.isChecked()) {
autoConflict = CONFLICT_OVERWRITE; 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. * Skip the export file and set the autoConflict if user set the "do it for all" switch button.
*/ */
public void skip() { public void skip() {
export(trackId, CONFLICT_SKIP); export(track, CONFLICT_SKIP);
if (viewBinding.exportProgressApplyToAll.isChecked()) { if (viewBinding.exportProgressApplyToAll.isChecked()) {
autoConflict = CONFLICT_SKIP; autoConflict = CONFLICT_SKIP;
@@ -14,6 +14,8 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.io.file.TrackFileFormat; 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) { public static boolean exportTrack(Context context, TrackFileFormat trackFileFormat, DocumentFile directory, Track track) {
TrackExporter trackExporter = trackFileFormat.createTrackExporter(context); TrackExporter trackExporter = trackFileFormat.createTrackExporter(context);
Uri exportDocumentFileUri = getExportDocumentFileUri(context, track.getId(), trackFileFormat, directory); Uri exportDocumentFileUri = getExportDocumentFileUri(context, track, trackFileFormat, directory);
if (exportDocumentFileUri == null) { if (exportDocumentFileUri == null) {
Log.e(TAG, "Couldn't create document file for export"); Log.e(TAG, "Couldn't create document file for export");
return false; return false;
@@ -62,8 +64,10 @@ public class ExportUtils {
} }
} }
public static boolean isExportFileExists(Track.Id trackId, String trackFileFormatExtension, List<String> filesName) { public static boolean isExportFileExists(UUID uuuid, String trackFileFormatExtension, List<String> filesName) {
return filesName.contains(getExportFileNameByTrackId(trackId, trackFileFormatExtension)); 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<String> getAllFiles(Context context, Uri directoryUri) { public static List<String> getAllFiles(Context context, Uri directoryUri) {
@@ -82,8 +86,8 @@ public class ExportUtils {
return fileNames; return fileNames;
} }
private static Uri getExportDocumentFileUri(Context context, Track.Id trackId, TrackFileFormat trackFileFormat, DocumentFile directory) { private static Uri getExportDocumentFileUri(Context context, Track track, TrackFileFormat trackFileFormat, DocumentFile directory) {
String exportFileName = getExportFileNameByTrackId(trackId, trackFileFormat.getExtension()); String exportFileName = getExportFileNameForTrack(track, trackFileFormat.getExtension());
Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName); Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName);
if (exportDocumentFileUri == null) { if (exportDocumentFileUri == null) {
final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName); final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName);
@@ -94,8 +98,8 @@ public class ExportUtils {
return exportDocumentFileUri; return exportDocumentFileUri;
} }
private static String getExportFileNameByTrackId(Track.Id trackId, String trackFileFormatExtension) { private static String getExportFileNameForTrack(Track track, String trackFileFormatExtension) {
return trackId.getId() + "." + trackFileFormatExtension; return track.getUuid().toString().substring(0, 8) + "_" + track.getName() + "." + trackFileFormatExtension;
} }
private static Uri findFile(Context context, Uri directoryUri, String exportFileName) { private static Uri findFile(Context context, Uri directoryUri, String exportFileName) {