- add default export directory

- add instant post workout track export
This commit is contained in:
thrillfall
2020-08-06 13:56:27 +02:00
committed by Dennis Guse
parent 257d8c1276
commit b270c45691
14 changed files with 253 additions and 5 deletions
@@ -161,7 +161,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
contentProviderUtils = new ContentProviderUtils(this);
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
trackId = null;
if (savedInstanceState != null) {
//Activity was recreated.
@@ -176,7 +176,6 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
}
recordingTrackPaused = PreferencesUtils.isRecordingTrackPausedDefault(this);
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback);
trackDataHub = new TrackDataHub(this);
@@ -0,0 +1,37 @@
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;
}
}
@@ -0,0 +1,40 @@
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);
}
}
}
@@ -0,0 +1,31 @@
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);
}
}
@@ -0,0 +1,45 @@
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();
}
}
}
@@ -47,6 +47,7 @@ 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;
@@ -62,6 +63,8 @@ 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}.
@@ -127,6 +130,7 @@ 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() {
@@ -186,17 +190,26 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
PreferencesUtils.unregister(this, sharedPreferenceChangeListener);
try {
voiceExecutor.shutdown();
} finally {
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);
@@ -411,6 +424,7 @@ 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);
@@ -1,6 +1,7 @@
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;
@@ -88,6 +89,17 @@ 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;
}
@Override
@@ -97,6 +109,20 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
updateUnits();
updateReset();
updateBluetooth();
updateExportDirectory();
setInstantExportPreferenceEnabled();
}
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);
}
@Override
@@ -206,4 +232,5 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
});
}
}
}
@@ -16,7 +16,7 @@ public class HackUtils {
*/
public static void invalidatePreference(@NonNull Preference preference) {
boolean isEnabled = preference.isEnabled();
preference.setEnabled(!isEnabled);
preference.setEnabled(isEnabled);
preference.setVisible(!isEnabled);
preference.setVisible(isEnabled);
}
}
@@ -173,4 +173,11 @@ public class IntentUtils {
.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
return new Pair<>(intent, photoUri);
}
public static void persistDirectoryAccessPermission(Context context, Intent resultData, Uri directoryUri) {
final int takeFlags = resultData.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
context.getContentResolver().takePersistableUriPermission(directoryUri, takeFlags);
}
}
@@ -19,6 +19,7 @@ package de.dennisguse.opentracks.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceManager;
@@ -337,6 +338,11 @@ public class PreferencesUtils {
return getInt(context, R.string.recording_gps_accuracy_key, RECORDING_GPS_ACCURACY);
}
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);
}
public static TrackFileFormat getExportTrackFileFormat(Context context) {
final String TRACKFILEFORMAT_NAME_DEFAULT = getString(context, R.string.export_trackfileformat_default, null);
String trackFileFormatName = getString(context, R.string.export_trackfileformat_key, TRACKFILEFORMAT_NAME_DEFAULT);
@@ -383,4 +389,20 @@ public class PreferencesUtils {
}
PreferenceManager.setDefaultValues(context, R.xml.settings, readAgain);
}
public static Uri getDefaultExportDirectoryUri(Context context)
{
String singleExportDirectorySettingsKey = getString(context, R.string.settings_default_export_directory_key, null);
if (singleExportDirectorySettingsKey == null) {
return null;
}
return Uri.parse(singleExportDirectorySettingsKey);
}
public static void setDefaultExportDirectoryUri(Context context, Uri directoryUri) {
setString(context,
R.string.settings_default_export_directory_key,
directoryUri.toString()
);
}
}