mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 17:43:06 +02:00
Export & import via Storage Access Framework.
This commit is contained in:
@@ -69,7 +69,7 @@ public class DescriptionGeneratorTest {
|
||||
track.setTripStatistics(stats);
|
||||
track.setCategory("hiking");
|
||||
String expected = //"Created by"
|
||||
"<a href='https://github.com/OpenTracksApp/opentracks'>OpenTracks</a><p>"
|
||||
"<a href='https://github.com/OpenTracksApp/OpenTracks'>OpenTracks</a><p>"
|
||||
+ "Name: -<br>"
|
||||
+ "Activity type: hiking<br>"
|
||||
+ "Description: -<br>"
|
||||
|
||||
@@ -25,7 +25,6 @@ limitations under the License.
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/ic_logo_color_24dp"
|
||||
android:label="@string/app_name"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:theme="@style/ThemeCustom">
|
||||
|
||||
<!-- Activities -->
|
||||
@@ -152,6 +151,4 @@ limitations under the License.
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
</manifest>
|
||||
|
||||
@@ -228,6 +228,7 @@ public class ContentProviderUtils {
|
||||
* @param dir the directory
|
||||
*/
|
||||
private void deleteDirectoryRecurse(Context context, File dir) {
|
||||
// TODO Does not work with
|
||||
if (FileUtils.isDirectory(dir)) {
|
||||
for (File child : dir.listFiles()) {
|
||||
deleteDirectoryRecurse(context, child);
|
||||
|
||||
@@ -16,21 +16,20 @@
|
||||
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.fragments.FileTypeDialogFragment;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
@@ -39,7 +38,6 @@ import de.dennisguse.opentracks.util.FileUtils;
|
||||
|
||||
/**
|
||||
* An activity for saving tracks to the external storage.
|
||||
* If saving a specific track, option to save it to a temp directory and play the track afterward.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
@@ -53,34 +51,39 @@ public class ExportActivity extends FragmentActivity implements FileTypeDialogFr
|
||||
private String directoryDisplayName;
|
||||
|
||||
private ExportAsyncTask exportAsyncTask;
|
||||
|
||||
private ProgressDialog progressDialog;
|
||||
|
||||
private int processedTrackCount;
|
||||
private int totalTrackCount;
|
||||
|
||||
private Uri directoryUri;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
|
||||
if (!FileUtils.isExternalStorageWriteable() || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
|
||||
} else {
|
||||
fileTypeDialogStart();
|
||||
}
|
||||
startActivityForResult(intent, EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent resultData) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData);
|
||||
if (requestCode == EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE) {
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
|
||||
Toast.makeText(this, R.string.external_storage_not_writable, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
// final int takeFlags = resultData.getFlags()
|
||||
// & (Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
// | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
//// Check for the freshest data.
|
||||
// getContentResolver().takePersistableUriPermission(uri, takeFlags);
|
||||
directoryUri = resultData.getData();
|
||||
fileTypeDialogStart();
|
||||
} else {
|
||||
Toast.makeText(this, R.string.external_storage_not_writable, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
private void fileTypeDialogStart() {
|
||||
@@ -89,21 +92,14 @@ public class ExportActivity extends FragmentActivity implements FileTypeDialogFr
|
||||
|
||||
@Override
|
||||
public void onFileTypeDone(TrackFileFormat trackFileFormat) {
|
||||
if (!FileUtils.isExternalStorageWriteable()) {
|
||||
Toast.makeText(this, R.string.external_storage_not_writable, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
File directory = new File(FileUtils.getPath(trackFileFormat.getExtension()));
|
||||
if (!FileUtils.ensureDirectoryExists(directory)) {
|
||||
Toast.makeText(this, R.string.external_storage_not_writable, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
return;
|
||||
DocumentFile pickedDirectory = DocumentFile.fromTreeUri(this, directoryUri);
|
||||
DocumentFile exportDirectory = pickedDirectory.findFile(FileUtils.SDCARD_TOP_DIR);
|
||||
if (exportDirectory == null) {
|
||||
exportDirectory = pickedDirectory.createDirectory(FileUtils.SDCARD_TOP_DIR);
|
||||
}
|
||||
|
||||
directoryDisplayName = FileUtils.getPathDisplayName(trackFileFormat.getExtension());
|
||||
exportAsyncTask = new ExportAsyncTask(this, trackFileFormat, directory);
|
||||
exportAsyncTask = new ExportAsyncTask(this, trackFileFormat, exportDirectory);
|
||||
exportAsyncTask.execute();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,16 +22,16 @@ import android.os.AsyncTask;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.content.ContentProviderUtils;
|
||||
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.util.FileUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.SystemUtils;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
|
||||
private static final String TAG = ExportAsyncTask.class.getSimpleName();
|
||||
private final TrackFileFormat trackFileFormat;
|
||||
private final File directory;
|
||||
private final DocumentFile directory;
|
||||
private final Context context;
|
||||
private final ContentProviderUtils contentProviderUtils;
|
||||
private ExportActivity exportActivity;
|
||||
@@ -63,7 +63,7 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
* @param trackFileFormat the track file format
|
||||
* @param directory the directory to write the file
|
||||
*/
|
||||
public ExportAsyncTask(ExportActivity exportActivity, TrackFileFormat trackFileFormat, File directory) {
|
||||
public ExportAsyncTask(ExportActivity exportActivity, TrackFileFormat trackFileFormat, DocumentFile directory) {
|
||||
this.exportActivity = exportActivity;
|
||||
this.trackFileFormat = trackFileFormat;
|
||||
this.directory = directory;
|
||||
@@ -156,13 +156,13 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
};
|
||||
|
||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context, tracks, trackExporterListener);
|
||||
|
||||
Track track = tracks[0];
|
||||
String fileName = FileUtils.buildUniqueFileName(directory, track.getName(), trackFileFormat.getExtension());
|
||||
File file = new File(directory, fileName);
|
||||
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
|
||||
if (trackExporter.writeTrack(context, fileOutputStream)) {
|
||||
String fileName = track.getId() + "." + trackFileFormat.getExtension();
|
||||
DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), fileName);
|
||||
|
||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(file.getUri())) {
|
||||
if (trackExporter.writeTrack(context, outputStream)) {
|
||||
return true;
|
||||
} else {
|
||||
if (!file.delete()) {
|
||||
|
||||
@@ -16,21 +16,20 @@
|
||||
|
||||
package de.dennisguse.opentracks.io.file.importer;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.fragments.FileTypeDialogFragment;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
@@ -38,8 +37,7 @@ import de.dennisguse.opentracks.util.DialogUtils;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
|
||||
/**
|
||||
* An activity to import files from the external storage. Optionally to import
|
||||
* one specific file.
|
||||
* An activity to import files from the external storage.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
@@ -50,70 +48,58 @@ public class ImportActivity extends FragmentActivity implements FileTypeDialogFr
|
||||
private static final int DIALOG_PROGRESS_ID = 0;
|
||||
private static final int DIALOG_RESULT_ID = 1;
|
||||
|
||||
private String directoryDisplayName;
|
||||
|
||||
private ImportAsyncTask importAsyncTask;
|
||||
private ProgressDialog progressDialog;
|
||||
|
||||
// the path on the external storage to import
|
||||
private String directoryDisplayName;
|
||||
|
||||
private int importedTrackCount;
|
||||
|
||||
private int totalTrackCount;
|
||||
|
||||
private Uri directoryUri;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (!FileUtils.isExternalStorageWriteable() || ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
|
||||
} else {
|
||||
fileTypeDialogStart();
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
||||
startActivityForResult(intent, EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent resultData) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData);
|
||||
if (requestCode == EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE) {
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
|
||||
Toast.makeText(this, R.string.external_storage_not_readable, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
// final int takeFlags = resultData.getFlags()
|
||||
// & (Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
// | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
//// Check for the freshest data.
|
||||
// getContentResolver().takePersistableUriPermission(uri, takeFlags);
|
||||
directoryUri = resultData.getData();
|
||||
fileTypeDialogStart();
|
||||
} else {
|
||||
Toast.makeText(this, R.string.external_storage_not_writable, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
|
||||
private void fileTypeDialogStart() {
|
||||
FileTypeDialogFragment.showDialog(getSupportFragmentManager(), R.string.import_selection_title, R.string.import_selection_option);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileTypeDone(TrackFileFormat trackFileFormat) {
|
||||
if (!FileUtils.isExternalStorageAvailable()) {
|
||||
Toast.makeText(this, R.string.external_storage_not_available, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
DocumentFile pickedDirectory = DocumentFile.fromTreeUri(this, directoryUri);
|
||||
|
||||
directoryDisplayName = FileUtils.getPathDisplayName(trackFileFormat.getExtension());
|
||||
String directoryPath = FileUtils.getPath(trackFileFormat.getExtension());
|
||||
if (!FileUtils.isDirectory(new File(directoryPath))) {
|
||||
Toast.makeText(this, getString(R.string.import_no_directory, directoryDisplayName), Toast.LENGTH_LONG)
|
||||
.show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO (still needed?): getLastNonConfiguration instance returned ExportAsyncTask before
|
||||
// Object retained = getLastNonConfigurationInstance();
|
||||
// if (retained instanceof ImportAsyncTask) {
|
||||
// importAsyncTask = (ImportAsyncTask) retained;
|
||||
// importAsyncTask.setActivity(this);
|
||||
// } else {
|
||||
importAsyncTask = new ImportAsyncTask(this, trackFileFormat, directoryPath);
|
||||
importAsyncTask = new ImportAsyncTask(this, trackFileFormat, pickedDirectory);
|
||||
importAsyncTask.execute();
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,8 +140,7 @@ public class ImportActivity extends FragmentActivity implements FileTypeDialogFr
|
||||
} else {
|
||||
iconId = R.drawable.ic_dialog_error_24dp;
|
||||
titleId = R.string.generic_error_title;
|
||||
message = getString(
|
||||
R.string.import_error, importedTrackCount, totalFiles, directoryDisplayName);
|
||||
message = getString(R.string.import_error, importedTrackCount, totalFiles, directoryDisplayName);
|
||||
}
|
||||
return new AlertDialog.Builder(this).setCancelable(true).setIcon(iconId)
|
||||
.setMessage(message).setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
|
||||
@@ -22,9 +22,10 @@ import android.os.AsyncTask;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -44,7 +45,7 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
|
||||
private static final String TAG = ImportAsyncTask.class.getSimpleName();
|
||||
private final TrackFileFormat trackFileFormat;
|
||||
private final String path;
|
||||
private final DocumentFile directory;
|
||||
// TODO Can be removed, or?
|
||||
private Context context;
|
||||
// TODO Use weak reference
|
||||
@@ -66,12 +67,12 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
*
|
||||
* @param importActivity the activity currently associated with this AsyncTask
|
||||
* @param trackFileFormat the track file format
|
||||
* @param path path to import GPX files
|
||||
* @param directory path to import GPX files
|
||||
*/
|
||||
public ImportAsyncTask(ImportActivity importActivity, TrackFileFormat trackFileFormat, String path) {
|
||||
public ImportAsyncTask(ImportActivity importActivity, TrackFileFormat trackFileFormat, DocumentFile directory) {
|
||||
this.importActivity = importActivity;
|
||||
this.trackFileFormat = trackFileFormat;
|
||||
this.path = path;
|
||||
this.directory = directory;
|
||||
context = importActivity.getApplicationContext();
|
||||
|
||||
completed = false;
|
||||
@@ -99,39 +100,26 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
try {
|
||||
Thread.currentThread().setPriority(Thread.MAX_PRIORITY); // TODO Should be set to previous level at the end of this method.
|
||||
// Get the wake lock if not recording or paused
|
||||
boolean isRecording = PreferencesUtils.isRecording(importActivity);
|
||||
boolean isPaused = PreferencesUtils.isRecordingTrackPaused(importActivity);
|
||||
if (!isRecording || isPaused) {
|
||||
wakeLock = SystemUtils.acquireWakeLock(importActivity, wakeLock);
|
||||
}
|
||||
/**
|
||||
* Gets a list of files.
|
||||
* If importAll is true, returns a list of the files under the path directory.
|
||||
* If importAll is false, returns a list containing just the path file.
|
||||
*/
|
||||
private static List<DocumentFile> getFiles(DocumentFile file, TrackFileFormat trackFileFormat) {
|
||||
List<DocumentFile> files = new ArrayList<>();
|
||||
|
||||
List<File> files = getFiles();
|
||||
totalTrackCount = files.size();
|
||||
if (totalTrackCount == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < totalTrackCount; i++) {
|
||||
if (isCancelled()) {
|
||||
// If cancelled, return true to show the number of files imported
|
||||
return true;
|
||||
for (DocumentFile candidate : file.listFiles()) {
|
||||
if (!candidate.isDirectory()) {
|
||||
String extension = FileUtils.getExtension(candidate.getName());
|
||||
if (trackFileFormat.getExtension().equals(extension)) {
|
||||
files.add(candidate);
|
||||
}
|
||||
if (importFile(files.get(i))) {
|
||||
importTrackCount++;
|
||||
}
|
||||
publishProgress(i + 1, totalTrackCount);
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
if (wakeLock != null && wakeLock.isHeld()) {
|
||||
wakeLock.release();
|
||||
} else {
|
||||
files.addAll(getFiles(candidate, trackFileFormat));
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,16 +147,49 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
try {
|
||||
Thread.currentThread().setPriority(Thread.MAX_PRIORITY); // TODO Should be set to previous level at the end of this method.
|
||||
// Get the wake lock if not recording or paused
|
||||
boolean isRecording = PreferencesUtils.isRecording(importActivity);
|
||||
boolean isPaused = PreferencesUtils.isRecordingTrackPaused(importActivity);
|
||||
if (!isRecording || isPaused) {
|
||||
wakeLock = SystemUtils.acquireWakeLock(importActivity, wakeLock);
|
||||
}
|
||||
|
||||
List<DocumentFile> files = getFiles(directory, trackFileFormat);
|
||||
totalTrackCount = files.size();
|
||||
|
||||
for (int i = 0; i < totalTrackCount; i++) {
|
||||
if (isCancelled()) {
|
||||
// If cancelled, return true to show the number of files imported
|
||||
return true;
|
||||
}
|
||||
if (importFile(files.get(i))) {
|
||||
importTrackCount++;
|
||||
}
|
||||
publishProgress(i + 1, totalTrackCount);
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
if (wakeLock != null && wakeLock.isHeld()) {
|
||||
wakeLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a file.
|
||||
*
|
||||
* @param file the file
|
||||
*/
|
||||
private boolean importFile(final File file) {
|
||||
private boolean importFile(final DocumentFile file) {
|
||||
TrackImporter trackImporter;
|
||||
if (trackFileFormat == TrackFileFormat.GPX) {
|
||||
trackImporter = new GpxFileTrackImporter(importActivity);
|
||||
} else { //KML or KMZ
|
||||
} else {
|
||||
//KML or KMZ
|
||||
String extension = FileUtils.getExtension(file.getName());
|
||||
if (TrackFileFormat.KML_ONLY_TRACK.getExtension().equals(extension)) {
|
||||
trackImporter = new KmlFileTrackImporter(importActivity, -1L);
|
||||
@@ -181,37 +202,12 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
trackId = trackImporter.importFile(fileInputStream);
|
||||
try (InputStream inputStream = context.getContentResolver().openInputStream(file.getUri())) {
|
||||
trackId = trackImporter.importFile(inputStream);
|
||||
return trackId != -1L;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to import file", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of files.
|
||||
* If importAll is true, returns a list of the files under the path directory.
|
||||
* If importAll is false, returns a list containing just the path file.
|
||||
*/
|
||||
private List<File> getFiles() {
|
||||
List<File> files = new ArrayList<>();
|
||||
File file = new File(path);
|
||||
|
||||
File[] candidates = file.listFiles();
|
||||
if (candidates == null) {
|
||||
return files;
|
||||
}
|
||||
for (File candidate : candidates) {
|
||||
if (!FileUtils.isDirectory(candidate)) {
|
||||
String extension = FileUtils.getExtension(candidate.getName());
|
||||
if (trackFileFormat.getExtension().equals(extension)) {
|
||||
files.add(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class FileUtils {
|
||||
/**
|
||||
* Our external storage directory.
|
||||
*/
|
||||
static final String SDCARD_TOP_DIR = "OpenTracks";
|
||||
public static final String SDCARD_TOP_DIR = "OpenTracks"; // TODO RENAME
|
||||
private static final String TRACK_PREFIX = "OpenTracks";
|
||||
/**
|
||||
* The maximum FAT32 path length. See the FAT32 spec at
|
||||
@@ -54,15 +54,6 @@ public class FileUtils {
|
||||
private FileUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the external storage is available.
|
||||
*/
|
||||
public static boolean isExternalStorageAvailable() {
|
||||
String state = Environment.getExternalStorageState();
|
||||
return Environment.MEDIA_MOUNTED.equals(state)
|
||||
|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the external storage is writable.
|
||||
*/
|
||||
@@ -76,6 +67,7 @@ public class FileUtils {
|
||||
*
|
||||
* @param dir the directory
|
||||
*/
|
||||
@Deprecated // TODO REMOVE" rewrite all locations this was used.
|
||||
public static boolean isDirectory(File dir) {
|
||||
return dir.exists() && dir.isDirectory();
|
||||
}
|
||||
@@ -86,6 +78,7 @@ public class FileUtils {
|
||||
* @return whether the directory exists (either already existed or was
|
||||
* successfully created)
|
||||
*/
|
||||
@Deprecated // TODO REMOVE" rewrite all locations this was used.
|
||||
public static boolean ensureDirectoryExists(File dir) {
|
||||
if (isDirectory(dir)) {
|
||||
return true;
|
||||
@@ -93,10 +86,12 @@ public class FileUtils {
|
||||
return dir.mkdirs();
|
||||
}
|
||||
|
||||
@Deprecated // TODO REMOVE" rewrite all locations this was used.
|
||||
public static File getPhotoDir() {
|
||||
return new File(getPath(PICTURES_DIR));
|
||||
}
|
||||
|
||||
@Deprecated // TODO REMOVE" rewrite all locations this was used.
|
||||
public static File getPhotoDir(long trackId) {
|
||||
return new File(getPath(PICTURES_DIR, TRACK_PREFIX + trackId));
|
||||
}
|
||||
@@ -122,6 +117,7 @@ public class FileUtils {
|
||||
*
|
||||
* @param components the components
|
||||
*/
|
||||
@Deprecated // TODO REMOVE" rewrite all locations this was used.
|
||||
public static String getPath(String... components) {
|
||||
return Environment.getExternalStorageDirectory() + getPathDisplayName(components);
|
||||
}
|
||||
|
||||
@@ -805,8 +805,7 @@ limitations under the License.
|
||||
dialog when there is no files to import.
|
||||
|
||||
%1$s the directory. E.g., '/kml'.">
|
||||
There were no files to import. Connect your device to your computer and place the files to
|
||||
import in %1$s.
|
||||
There were no files to import. Connect your device to your computer and place the files to import in %1$s.
|
||||
</string>
|
||||
<string name="import_no_file_title" translation_description="When importing from the external storage, the title in the result
|
||||
dialog when there is no files to import.">
|
||||
|
||||
Reference in New Issue
Block a user