forked from upstream-mirrors/OpenTracks
Refactor post-workout export.
This commit is contained in:
+3
-2
@@ -47,8 +47,9 @@ MarkerDetailActivity --> CoordinateOnMapIntent : URI
|
||||
SettingsActivity --> AboutActivity
|
||||
SettingsActivity --> HelpActivity
|
||||
SettingsActivity --> ExportActivity
|
||||
SettingsActivity --> DirectoryChooserActivity
|
||||
SettingsActivity --> DirectoryChooserActivity
|
||||
SettingsActivity --> DirectoryChooserActivity$ImportDirectoryChooserActivity
|
||||
SettingsActivity --> DirectoryChooserActivity$ExportDirectoryChooserActivity
|
||||
SettingsActivity --> DirectoryChooserActivity$DefaultTrackExportDirectoryChooserActivity
|
||||
DirectoryChooserActivity$ImportDirectoryChooserActivity --> ImportActivity
|
||||
DirectoryChooserActivity$ExportDirectoryChooserActivity --> ExportActivity
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ limitations under the License.
|
||||
<activity android:name=".AggregatedStatisticsActivity" />
|
||||
|
||||
<activity android:name=".io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserActivity" />
|
||||
<activity android:name=".io.file.importer.DirectoryChooserActivity$DefaultTrackExportDirectoryChooserActivity" />
|
||||
|
||||
<activity
|
||||
android:name=".io.file.exporter.ExportActivity"
|
||||
@@ -171,8 +172,6 @@ limitations under the License.
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".io.file.importer.DefaultTrackExportDirectoryChooserActivity" />
|
||||
<activity android:name=".io.file.InitiateExportActivity" />
|
||||
|
||||
<provider
|
||||
android:name=".content.provider.ShareContentProvider"
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -30,18 +29,13 @@ import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.io.file.ExportFile;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
import de.dennisguse.opentracks.util.DialogUtils;
|
||||
import de.dennisguse.opentracks.util.ExportUtils;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
|
||||
public class ExportProgressDialogFragment extends DialogFragment {
|
||||
@@ -197,7 +191,7 @@ public class ExportProgressDialogFragment extends DialogFragment {
|
||||
|
||||
cursor.moveToPosition(i);
|
||||
Track track = contentProviderUtils.createTrack(cursor);
|
||||
if (track != null && exportTrack(context, track)) {
|
||||
if (track != null && ExportUtils.exportTrack(context, trackFileFormat, directory, track)) {
|
||||
trackExportSuccessCount++;
|
||||
}
|
||||
}
|
||||
@@ -205,36 +199,6 @@ public class ExportProgressDialogFragment extends DialogFragment {
|
||||
onExportCompleted(trackExportSuccessCount, trackCount);
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean exportTrack(Context context, Track track) {
|
||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
||||
|
||||
DocumentFile exportDocumentFile = ExportFile.getExportDocumentFile(
|
||||
track.getId(),
|
||||
trackFileFormat.getExtension(),
|
||||
directory,
|
||||
trackFileFormat.getMimeType()
|
||||
);
|
||||
|
||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(exportDocumentFile.getUri())) {
|
||||
if (trackExporter.writeTrack(track, outputStream)) {
|
||||
return true;
|
||||
} else {
|
||||
if (!exportDocumentFile.delete()) {
|
||||
Log.e(TAG, "Unable to delete exportDocumentFile");
|
||||
}
|
||||
Log.e(TAG, "Unable to export track");
|
||||
return false;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "Unable to open exportDocumentFile " + exportDocumentFile.getName(), e);
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to close exportDocumentFile output stream", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface DismissCallback {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package de.dennisguse.opentracks.io.file;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
|
||||
public class ExportFile {
|
||||
|
||||
public static DocumentFile getExportDocumentFile(Track.Id trackId, String trackFileFormatExtension, DocumentFile directory, String mimeType) {
|
||||
String fileName = getExportFileNameByTrackId(trackId, trackFileFormatExtension);
|
||||
DocumentFile file = directory.findFile(fileName);
|
||||
if (file == null) {
|
||||
file = directory.createFile(mimeType, fileName);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private static String getExportFileNameByTrackId(Track.Id trackId, String trackFileFormatExtension) {
|
||||
return trackId.getId() + "." + trackFileFormatExtension;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package de.dennisguse.opentracks.io.file;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import de.dennisguse.opentracks.io.file.exporter.ExportActivity;
|
||||
import de.dennisguse.opentracks.io.file.importer.DirectoryChooserActivity;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
public class InitiateExportActivity extends AppCompatActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Uri directoryUri = PreferencesUtils.getDefaultExportDirectoryUri(this);
|
||||
if (directoryUri != null) {
|
||||
startActivity(createExportAllIntent(directoryUri));
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = IntentUtils.newIntent(this, DirectoryChooserActivity.ExportDirectoryChooserActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
protected Intent createExportAllIntent(Uri directoryUri) {
|
||||
Intent intent = IntentUtils.newIntent(this, ExportActivity.class);
|
||||
intent.putExtra(ExportActivity.EXTRA_DIRECTORY_URI_KEY, directoryUri);
|
||||
intent.putExtra(ExportActivity.EXTRA_TRACKFILEFORMAT_KEY, PreferencesUtils.getExportTrackFileFormat(this));
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.io.file.ExportFile;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
|
||||
public class InstantPostWorkoutExport {
|
||||
|
||||
private static final String TAG = InstantPostWorkoutExport.class.getSimpleName();
|
||||
|
||||
public static void exportTrackToUri(Uri directoryUri, Context context, ContentProviderUtils contentProviderUtils, TrackFileFormat trackFileFormat, Track.Id trackId) {
|
||||
DocumentFile directory = DocumentFile.fromTreeUri(context, directoryUri);
|
||||
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
DocumentFile file = ExportFile.getExportDocumentFile(trackId, trackFileFormat.getExtension(), directory, trackFileFormat.getExtension());
|
||||
|
||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(file.getUri())) {
|
||||
TrackExportThread trackExportThread = new TrackExportThread(outputStream, context, trackFileFormat, track);
|
||||
trackExportThread.run();
|
||||
Toast.makeText(context, R.string.toast_message_instant_track_was_exported, Toast.LENGTH_SHORT).show();
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "Unable to open file " + file.getName(), e);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to close file output stream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
|
||||
public class TrackExportThread extends Thread {
|
||||
|
||||
private OutputStream outputStream;
|
||||
private Context context;
|
||||
private TrackFileFormat trackFileFormat;
|
||||
private Track track;
|
||||
|
||||
public TrackExportThread(OutputStream outputStream, Context context, TrackFileFormat trackFileFormat, Track track) {
|
||||
this.outputStream = outputStream;
|
||||
this.context = context;
|
||||
this.trackFileFormat = trackFileFormat;
|
||||
this.track = track;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
||||
trackExporter.writeTrack(track, outputStream);
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
package de.dennisguse.opentracks.io.file.importer;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
import static de.dennisguse.opentracks.util.IntentUtils.persistDirectoryAccessPermission;
|
||||
|
||||
public class DefaultTrackExportDirectoryChooserActivity extends AppCompatActivity {
|
||||
|
||||
private static final int DIRECTORY_PICKER_REQUEST_CODE = 6;
|
||||
|
||||
@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);
|
||||
|
||||
startActivityForResult(intent, DIRECTORY_PICKER_REQUEST_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent resultData) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData);
|
||||
if (requestCode == DIRECTORY_PICKER_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri directoryUri = resultData.getData();
|
||||
|
||||
PreferencesUtils.setDefaultExportDirectoryUri(this, directoryUri);
|
||||
persistDirectoryAccessPermission(getApplicationContext(), resultData, directoryUri);
|
||||
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+61
-7
@@ -4,9 +4,11 @@ import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.DocumentsContract;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import de.dennisguse.opentracks.io.file.exporter.ExportActivity;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
@@ -21,31 +23,42 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
configureDirectoryChooserIntent(intent);
|
||||
|
||||
startActivityForResult(intent, DIRECTORY_PICKER_REQUEST_CODE);
|
||||
DocumentFile directoryUri = configureDirectoryChooserIntent(intent);
|
||||
if (directoryUri == null) {
|
||||
startActivityForResult(intent, DIRECTORY_PICKER_REQUEST_CODE);
|
||||
} else {
|
||||
startActivity(createNextActivityIntent(directoryUri.getUri())); //TODO Refactor to DocumentFile
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent resultData) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData);
|
||||
onActivityResultCustom(requestCode, resultCode, resultData);
|
||||
}
|
||||
|
||||
protected void onActivityResultCustom(int requestCode, int resultCode, @Nullable Intent resultData) {
|
||||
if (requestCode == DIRECTORY_PICKER_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri directoryUri = resultData.getData();
|
||||
|
||||
startActivity(createNextActivityIntent(directoryUri));
|
||||
}
|
||||
finish();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
protected void configureDirectoryChooserIntent(Intent intent) {
|
||||
/**
|
||||
* @return null if directory needs to be selected.
|
||||
*/
|
||||
protected DocumentFile configureDirectoryChooserIntent(Intent intent) {
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract Intent createNextActivityIntent(Uri directoryUri);
|
||||
|
||||
|
||||
public static class ImportDirectoryChooserActivity extends DirectoryChooserActivity {
|
||||
|
||||
@Override
|
||||
@@ -58,6 +71,14 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
|
||||
public static class ExportDirectoryChooserActivity extends DirectoryChooserActivity {
|
||||
|
||||
@Override
|
||||
protected DocumentFile configureDirectoryChooserIntent(Intent intent) {
|
||||
super.configureDirectoryChooserIntent(intent);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
|
||||
return PreferencesUtils.getDefaultExportDirectoryUri(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent createNextActivityIntent(Uri directoryUri) {
|
||||
Intent intent = IntentUtils.newIntent(this, ExportActivity.class);
|
||||
@@ -65,11 +86,44 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
||||
intent.putExtra(ExportActivity.EXTRA_TRACKFILEFORMAT_KEY, PreferencesUtils.getExportTrackFileFormat(this));
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DefaultTrackExportDirectoryChooserActivity extends DirectoryChooserActivity {
|
||||
|
||||
@Override
|
||||
protected void configureDirectoryChooserIntent(Intent intent) {
|
||||
protected void onActivityResultCustom(int requestCode, int resultCode, @Nullable Intent resultData) {
|
||||
if (requestCode == DIRECTORY_PICKER_REQUEST_CODE) {
|
||||
switch (resultCode) {
|
||||
case RESULT_OK:
|
||||
Uri directoryUri = resultData.getData();
|
||||
|
||||
PreferencesUtils.setDefaultExportDirectoryUri(this, directoryUri);
|
||||
IntentUtils.persistDirectoryAccessPermission(getApplicationContext(), resultData, directoryUri);
|
||||
break;
|
||||
case RESULT_CANCELED:
|
||||
PreferencesUtils.setDefaultExportDirectoryUri(this, null);
|
||||
//TODO Remove stored permission contentResolver.releasePersistableUriPermission
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DocumentFile configureDirectoryChooserIntent(Intent intent) {
|
||||
super.configureDirectoryChooserIntent(intent);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
if (PreferencesUtils.isDefaultExportDirectoryUri(this)) {
|
||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, PreferencesUtils.getDefaultExportDirectoryUri(this).getUri());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent createNextActivityIntent(Uri directoryUri) {
|
||||
finish();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.services.handlers.HandlerServer;
|
||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||
import de.dennisguse.opentracks.services.sensors.ElevationSumManager;
|
||||
@@ -55,6 +54,7 @@ import de.dennisguse.opentracks.services.tasks.AnnouncementPeriodicTaskFactory;
|
||||
import de.dennisguse.opentracks.services.tasks.PeriodicTaskExecutor;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
import de.dennisguse.opentracks.util.ExportUtils;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
@@ -63,8 +63,6 @@ import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
import de.dennisguse.opentracks.util.TrackNameUtils;
|
||||
import de.dennisguse.opentracks.util.TrackPointUtils;
|
||||
|
||||
import static de.dennisguse.opentracks.io.file.exporter.InstantPostWorkoutExport.exportTrackToUri;
|
||||
|
||||
/**
|
||||
* A background service that registers a location listener and records track points.
|
||||
* Track points are saved to the {@link CustomContentProvider}.
|
||||
@@ -130,7 +128,6 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
private HandlerServer handlerServer;
|
||||
|
||||
private List<TrackRecordingServiceCallback> listeners = new ArrayList<>();
|
||||
private Track.Id lastTrackId;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
@@ -197,19 +194,11 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
voiceExecutor = null;
|
||||
}
|
||||
|
||||
if (PreferencesUtils.shouldInstantExportAfterWorkout(getApplicationContext())) {
|
||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(this);
|
||||
|
||||
Uri directoryUri = PreferencesUtils.getDefaultExportDirectoryUri(getApplicationContext());
|
||||
exportTrackToUri(directoryUri, getApplicationContext(), contentProviderUtils, trackFileFormat, lastTrackId);
|
||||
}
|
||||
|
||||
contentProviderUtils = null;
|
||||
|
||||
binder.detachFromService();
|
||||
binder = null;
|
||||
|
||||
|
||||
// This should be the next to last operation
|
||||
wakeLock = SystemUtils.releaseWakeLock(wakeLock);
|
||||
|
||||
@@ -424,7 +413,6 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
|
||||
// Need to remember the recordingTrackId before setting it to -1L
|
||||
Track.Id trackId = recordingTrackId;
|
||||
lastTrackId = recordingTrackId;
|
||||
boolean wasPaused = recordingTrackPaused;
|
||||
|
||||
updateRecordingState(null, true);
|
||||
@@ -442,6 +430,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
updateTrackTotalTime(track);
|
||||
}
|
||||
}
|
||||
|
||||
ExportUtils.postWorkoutExport(this, track);
|
||||
|
||||
endRecording(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package de.dennisguse.opentracks.settings;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.ListPreference;
|
||||
@@ -89,17 +89,13 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
|
||||
|
||||
setExportTrackFileFormatOptions();
|
||||
setWheelCircumferenceInputFilter();
|
||||
Preference instantExportDirectoryPreference = findPreference(getString(R.string.preference_key_default_export_uri));
|
||||
if (instantExportDirectoryPreference != null) {
|
||||
instantExportDirectoryPreference.setSummaryProvider(preference -> {
|
||||
Uri uri = PreferencesUtils.getDefaultExportDirectoryUri(getContext());
|
||||
return uri != null ? uri.getPath() : getString(R.string.summay_default_export_directory_not_set_yet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDefaultExportDirectorySet() {
|
||||
return PreferencesUtils.getDefaultExportDirectoryUri(getContext()) != null;
|
||||
Preference instantExportDirectoryPreference = findPreference(getString(R.string.settings_default_export_directory_key));
|
||||
instantExportDirectoryPreference.setSummaryProvider(preference -> {
|
||||
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(getContext());
|
||||
//Use same value for not set as Androidx ListPreference and EditTextPreference
|
||||
return directory != null ? directory.getName() : getString(R.string.not_set);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,20 +105,13 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
|
||||
updateUnits();
|
||||
updateReset();
|
||||
updateBluetooth();
|
||||
updateExportDirectory();
|
||||
setInstantExportPreferenceEnabled();
|
||||
|
||||
updatePostWorkoutExport();
|
||||
}
|
||||
|
||||
private void setInstantExportPreferenceEnabled() {
|
||||
Preference instantExportEnabledPreference = findPreference("instantExportEnabled");
|
||||
assert instantExportEnabledPreference != null;
|
||||
instantExportEnabledPreference.setEnabled(isDefaultExportDirectorySet());
|
||||
}
|
||||
|
||||
private void updateExportDirectory() {
|
||||
Preference defaultExportDirectoryPreference = findPreference("defaultExportUri");
|
||||
assert defaultExportDirectoryPreference != null;
|
||||
HackUtils.invalidatePreference(defaultExportDirectoryPreference);
|
||||
private void updatePostWorkoutExport() {
|
||||
Preference instantExportEnabledPreference = findPreference(getString(R.string.post_workout_export_enabled_key));
|
||||
instantExportEnabledPreference.setEnabled(PreferencesUtils.isDefaultExportDirectoryUri(getContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package de.dennisguse.opentracks.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
|
||||
public class ExportUtils {
|
||||
|
||||
private static final String TAG = ExportUtils.class.getSimpleName();
|
||||
|
||||
public static void postWorkoutExport(Context context, Track track) {
|
||||
if (PreferencesUtils.shouldInstantExportAfterWorkout(context)) {
|
||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
||||
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(context);
|
||||
|
||||
exportTrack(context, trackFileFormat, directory, track);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean exportTrack(Context context, TrackFileFormat trackFileFormat, DocumentFile directory, Track track) {
|
||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
||||
|
||||
DocumentFile exportDocumentFile = ExportUtils.getExportDocumentFile(track.getId(), trackFileFormat.getExtension(), directory, trackFileFormat.getMimeType());
|
||||
|
||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(exportDocumentFile.getUri())) {
|
||||
if (trackExporter.writeTrack(track, outputStream)) {
|
||||
return true;
|
||||
} else {
|
||||
if (!exportDocumentFile.delete()) {
|
||||
Log.e(TAG, "Unable to delete exportDocumentFile");
|
||||
}
|
||||
Log.e(TAG, "Unable to export track");
|
||||
return false;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "Unable to open exportDocumentFile " + exportDocumentFile.getName(), e);
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to close exportDocumentFile output stream", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentFile getExportDocumentFile(Track.Id trackId, String trackFileFormatExtension, DocumentFile directory, String mimeType) {
|
||||
String fileName = getExportFileNameByTrackId(trackId, trackFileFormatExtension);
|
||||
DocumentFile file = directory.findFile(fileName);
|
||||
if (file == null) {
|
||||
file = directory.createFile(mimeType, fileName);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private static String getExportFileNameByTrackId(Track.Id trackId, String trackFileFormatExtension) {
|
||||
return trackId.getId() + "." + trackFileFormatExtension;
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,10 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
@@ -35,6 +37,8 @@ import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
*/
|
||||
public class PreferencesUtils {
|
||||
|
||||
private final static String TAG = PreferencesUtils.class.getSimpleName();
|
||||
|
||||
private PreferencesUtils() {
|
||||
}
|
||||
|
||||
@@ -339,8 +343,8 @@ public class PreferencesUtils {
|
||||
}
|
||||
|
||||
public static boolean shouldInstantExportAfterWorkout(Context context) {
|
||||
final boolean INSTANT_POST_WORKOUT_EXPORT_DEFAULT = context.getResources().getBoolean(R.bool.instant_export_enabled_default);
|
||||
return getBoolean(context, R.string.instant_export_enabled_key, INSTANT_POST_WORKOUT_EXPORT_DEFAULT);
|
||||
final boolean INSTANT_POST_WORKOUT_EXPORT_DEFAULT = context.getResources().getBoolean(R.bool.post_workout_export_enabled_default);
|
||||
return getBoolean(context, R.string.post_workout_export_enabled_key, INSTANT_POST_WORKOUT_EXPORT_DEFAULT);
|
||||
}
|
||||
|
||||
public static TrackFileFormat getExportTrackFileFormat(Context context) {
|
||||
@@ -390,19 +394,25 @@ public class PreferencesUtils {
|
||||
PreferenceManager.setDefaultValues(context, R.xml.settings, readAgain);
|
||||
}
|
||||
|
||||
public static Uri getDefaultExportDirectoryUri(Context context)
|
||||
{
|
||||
public static DocumentFile getDefaultExportDirectoryUri(Context context) {
|
||||
String singleExportDirectorySettingsKey = getString(context, R.string.settings_default_export_directory_key, null);
|
||||
if (singleExportDirectorySettingsKey == null) {
|
||||
return null;
|
||||
}
|
||||
return Uri.parse(singleExportDirectorySettingsKey);
|
||||
try {
|
||||
return DocumentFile.fromTreeUri(context, Uri.parse(singleExportDirectorySettingsKey));
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Could not decode default export directory: " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void setDefaultExportDirectoryUri(Context context, Uri directoryUri) {
|
||||
setString(context,
|
||||
R.string.settings_default_export_directory_key,
|
||||
directoryUri.toString()
|
||||
);
|
||||
String value = directoryUri != null ? directoryUri.toString() : null;
|
||||
setString(context, R.string.settings_default_export_directory_key, value);
|
||||
}
|
||||
|
||||
public static boolean isDefaultExportDirectoryUri(Context context) {
|
||||
return getDefaultExportDirectoryUri(context) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,8 @@
|
||||
<string name="settings_sensor_bluetooth_cycling_speed_wheel_circumference_default" translatable="false">2135</string>
|
||||
|
||||
<string name="settings_default_export_directory_key" translatable="false">settingsDefaultExportDirectory</string>
|
||||
<bool name="instant_export_enabled_default" translatable="false">false</bool>
|
||||
<string name="instant_export_enabled_title" translatable="false">Instant post-workout export</string>
|
||||
<string name="instant_export_enabled_key" translatable="false">instantExportEnabled</string>
|
||||
<string name="settings_default_export_uri_key" translatable="false">defaultExportUri</string>
|
||||
<string name="post_workout_export_enabled_key" translatable="false">instantExportEnabled</string>
|
||||
<bool name="post_workout_export_enabled_default" translatable="false">false</bool>
|
||||
|
||||
<string name="default_activity_key" translatable="false">defaultActivity</string>
|
||||
<string name="default_activity_default" translatable="false">@string/activity_type_unknown</string>
|
||||
|
||||
@@ -602,8 +602,9 @@ limitations under the License.
|
||||
<string name="hold_to_stop">Hold to stop recording</string>
|
||||
<string name="hold_to_pause">Hold to pause recording</string>
|
||||
<string name="toast_message_instant_track_was_exported">Last track exported</string>
|
||||
<string name="instant_export_enabled_summary">Export track to storage after recording finished</string>
|
||||
<string name="settings_default_export_uri_title">Set track export directory</string>
|
||||
<string name="preference_key_default_export_uri">defaultExportUri</string>
|
||||
<string name="summay_default_export_directory_not_set_yet">not set yet</string>
|
||||
|
||||
<string name="instant_export_enabled_summary">Export track to storage after recording is finished</string>
|
||||
<string name="instant_export_enabled_title">Instant post-workout export</string>
|
||||
|
||||
<string name="settings_default_export_uri_title">Track export directory</string>
|
||||
</resources>
|
||||
|
||||
@@ -52,11 +52,11 @@ limitations under the License.
|
||||
android:key="@string/stats_show_coordinate_key"
|
||||
android:title="@string/settings_stats_coordinate" />
|
||||
<ListPreference
|
||||
android:key="@string/night_mode_key"
|
||||
android:title="@string/settings_night_mode_title"
|
||||
android:defaultValue="@string/night_mode_default"
|
||||
android:entries="@array/night_mode_options"
|
||||
android:entryValues="@array/night_mode_values"
|
||||
android:key="@string/night_mode_key"
|
||||
android:title="@string/settings_night_mode_title"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
|
||||
@@ -151,22 +151,21 @@ limitations under the License.
|
||||
</Preference>
|
||||
<Preference android:title="@string/menu_export_all">
|
||||
<intent
|
||||
android:targetClass="de.dennisguse.opentracks.io.file.InitiateExportActivity"
|
||||
android:targetClass="de.dennisguse.opentracks.io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserActivity"
|
||||
android:targetPackage="@string/applicationId" />
|
||||
</Preference>
|
||||
<Preference
|
||||
android:key="@string/settings_default_export_directory_key"
|
||||
android:title="@string/settings_default_export_uri_title">
|
||||
<intent
|
||||
android:targetClass="de.dennisguse.opentracks.io.file.importer.DirectoryChooserActivity$DefaultTrackExportDirectoryChooserActivity"
|
||||
android:targetPackage="@string/applicationId" />
|
||||
</Preference>
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="@bool/instant_export_enabled_default"
|
||||
android:key="@string/instant_export_enabled_key"
|
||||
android:defaultValue="@bool/post_workout_export_enabled_default"
|
||||
android:key="@string/post_workout_export_enabled_key"
|
||||
android:summary="@string/instant_export_enabled_summary"
|
||||
android:title="@string/instant_export_enabled_title" />
|
||||
<Preference
|
||||
android:key="@string/settings_default_export_uri_key"
|
||||
android:title="@string/settings_default_export_uri_title"
|
||||
>
|
||||
<intent
|
||||
android:targetClass="de.dennisguse.opentracks.io.file.importer.DefaultTrackExportDirectoryChooserActivity"
|
||||
android:targetPackage="@string/applicationId" />
|
||||
</Preference>
|
||||
<ListPreference
|
||||
android:defaultValue="@string/export_trackfileformat_default"
|
||||
android:key="@string/export_trackfileformat_key"
|
||||
|
||||
Reference in New Issue
Block a user