Export & import via Storage Access Framework.

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