forked from upstream-mirrors/OpenTracks
fix #1025 exportdir failed to create document
fix #254 illegal filename characters
This commit is contained in:
@@ -29,6 +29,7 @@ import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
|
||||
/**
|
||||
* A content provider that mimics the behavior of {@link androidx.core.content.FileProvider}, which shares virtual (non-existing) KML-files.
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.ResultReceiver;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.JobIntentService;
|
||||
@@ -24,6 +25,7 @@ public class ExportService extends JobIntentService {
|
||||
private static final String EXTRA_TRACK_ID = "extra_track_id";
|
||||
private static final String EXTRA_TRACK_FILE_FORMAT = "extra_track_file_format";
|
||||
private static final String EXTRA_DIRECTORY_URI = "extra_directory_uri";
|
||||
private static final String TAG = ExportService.class.getSimpleName();
|
||||
|
||||
public static void enqueue(Context context, ExportServiceResultReceiver receiver, Track.Id trackId, TrackFileFormat trackFileFormat, Uri directoryUri) {
|
||||
Intent intent = new Intent(context, JobService.class);
|
||||
@@ -42,18 +44,23 @@ public class ExportService extends JobIntentService {
|
||||
TrackFileFormat trackFileFormat = (TrackFileFormat) intent.getSerializableExtra(EXTRA_TRACK_FILE_FORMAT);
|
||||
Uri directoryUri = intent.getParcelableExtra(EXTRA_DIRECTORY_URI);
|
||||
|
||||
// Prepare resultCode and bundle to send to the receiver.
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID, trackId);
|
||||
|
||||
// Build directory file.
|
||||
DocumentFile directoryFile = DocumentFile.fromTreeUri(this, directoryUri);
|
||||
if (directoryFile == null || !directoryFile.canWrite()) {
|
||||
Log.e(TAG, "Can't write to directory: " + directoryFile);
|
||||
resultReceiver.send(ExportServiceResultReceiver.RESULT_CODE_ERROR, bundle);
|
||||
return;
|
||||
}
|
||||
|
||||
// Export.
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
boolean success = ExportUtils.exportTrack(this, trackFileFormat, directoryFile, track);
|
||||
|
||||
// Prepare resultCode and bundle to send to the receiver.
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID, trackId);
|
||||
|
||||
// Send result to the receiver.
|
||||
int resultCode = success ? ExportServiceResultReceiver.RESULT_CODE_SUCCESS : ExportServiceResultReceiver.RESULT_CODE_ERROR;
|
||||
resultReceiver.send(resultCode, bundle);
|
||||
|
||||
+22
-4
@@ -3,10 +3,12 @@ package de.dennisguse.opentracks.io.file.importer;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.DocumentsContract;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
@@ -24,7 +26,7 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
DocumentFile directoryUri = configureDirectoryChooserIntent(intent);
|
||||
if (directoryUri == null) {
|
||||
if (!isDirectoryValid(directoryUri)) {
|
||||
startActivityForResult(intent, DIRECTORY_PICKER_REQUEST_CODE);
|
||||
} else {
|
||||
startActivity(createNextActivityIntent(directoryUri.getUri())); //TODO Refactor to DocumentFile
|
||||
@@ -32,6 +34,10 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isDirectoryValid(final DocumentFile directoryUri) {
|
||||
return directoryUri != null && directoryUri.isDirectory() && directoryUri.canRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent resultData) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData);
|
||||
@@ -83,6 +89,11 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
return PreferencesUtils.getDefaultExportDirectoryUri(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isDirectoryValid(final DocumentFile directoryUri) {
|
||||
return super.isDirectoryValid(directoryUri) && directoryUri.canWrite();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent createNextActivityIntent(Uri directoryUri) {
|
||||
Intent intent = IntentUtils.newIntent(this, ExportActivity.class);
|
||||
@@ -102,7 +113,7 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
Uri directoryUri = resultData.getData();
|
||||
|
||||
PreferencesUtils.setDefaultExportDirectoryUri(directoryUri);
|
||||
IntentUtils.persistDirectoryAccessPermission(getApplicationContext(), directoryUri);
|
||||
IntentUtils.persistDirectoryAccessPermission(getApplicationContext(), directoryUri, resultData.getFlags());
|
||||
break;
|
||||
case RESULT_CANCELED:
|
||||
PreferencesUtils.setDefaultExportDirectoryUri(null);
|
||||
@@ -114,12 +125,19 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isDirectoryValid(final DocumentFile directoryUri) {
|
||||
return super.isDirectoryValid(directoryUri) && directoryUri.canWrite();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DocumentFile configureDirectoryChooserIntent(Intent intent) {
|
||||
super.configureDirectoryChooserIntent(intent);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
||||
if (PreferencesUtils.isDefaultExportDirectoryUri(this)) {
|
||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, PreferencesUtils.getDefaultExportDirectoryUri(this).getUri());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, PreferencesUtils.getDefaultExportDirectoryUri(this).getUri());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ public class ExportUtils {
|
||||
}
|
||||
|
||||
private static String getExportFileNameForTrack(Track track, String trackFileFormatExtension) {
|
||||
return track.getUuid().toString().substring(0, 8) + "_" + track.getName() + "." + trackFileFormatExtension;
|
||||
return track.getUuid().toString().substring(0, 8) + "_" + FileUtils.sanitizeFileName(track.getName()) + "." + trackFileFormatExtension;
|
||||
}
|
||||
|
||||
private static Uri findFile(Context context, Uri directoryUri, String exportFileName) {
|
||||
|
||||
@@ -149,7 +149,6 @@ public class FileUtils {
|
||||
*
|
||||
* @param name name
|
||||
*/
|
||||
// TODO Check if this function is still needed.
|
||||
public static String sanitizeFileName(String name) {
|
||||
StringBuilder builder = new StringBuilder(name.length());
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
|
||||
@@ -92,8 +92,9 @@ public class IntentUtils {
|
||||
continue;
|
||||
}
|
||||
|
||||
Pair<Uri, String> uriTrackFile = ShareContentProvider.createURI(trackId, track.getName(), PreferencesUtils.getExportTrackFileFormat());
|
||||
Pair<Uri, String> uriSharePicture = ShareContentProvider.createURI(trackId, track.getName(), TrackFileFormat.SHARE_PICTURE_PNG);
|
||||
String trackName = FileUtils.sanitizeFileName(track.getName());
|
||||
Pair<Uri, String> uriTrackFile = ShareContentProvider.createURI(trackId, trackName, PreferencesUtils.getExportTrackFileFormat());
|
||||
Pair<Uri, String> uriSharePicture = ShareContentProvider.createURI(trackId, trackName, TrackFileFormat.SHARE_PICTURE_PNG);
|
||||
|
||||
uris.addAll(Arrays.asList(uriSharePicture.first, uriTrackFile.first));
|
||||
}
|
||||
@@ -203,8 +204,8 @@ public class IntentUtils {
|
||||
return new Pair<>(intent, photoUri);
|
||||
}
|
||||
|
||||
public static void persistDirectoryAccessPermission(Context context, Uri directoryUri) {
|
||||
int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
||||
context.getContentResolver().takePersistableUriPermission(directoryUri, flags);
|
||||
public static void persistDirectoryAccessPermission(Context context, Uri directoryUri, int existingFlags) {
|
||||
int newFlags = existingFlags | (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
context.getContentResolver().takePersistableUriPermission(directoryUri, newFlags);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user