Show on map: draft via sharing temporary file.

This commit is contained in:
Dennis Guse
2019-08-18 18:21:14 +02:00
parent f537cc7321
commit 8296c0194d
2 changed files with 72 additions and 6 deletions
@@ -25,6 +25,7 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.database.Cursor; import android.database.Cursor;
import android.location.LocationManager; import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.StrictMode; import android.os.StrictMode;
import android.provider.Settings; import android.provider.Settings;
@@ -46,20 +47,30 @@ import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;
import androidx.cursoradapter.widget.ResourceCursorAdapter; import androidx.cursoradapter.widget.ResourceCursorAdapter;
import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager;
import androidx.loader.app.LoaderManager.LoaderCallbacks; import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.CursorLoader; import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader; import androidx.loader.content.Loader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Locale; import java.util.Locale;
import de.dennisguse.opentracks.content.ContentProviderUtils; import de.dennisguse.opentracks.content.ContentProviderUtils;
import de.dennisguse.opentracks.content.Track;
import de.dennisguse.opentracks.content.TracksColumns; import de.dennisguse.opentracks.content.TracksColumns;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment; import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.FileTrackExporter;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
import de.dennisguse.opentracks.services.ITrackRecordingService; import de.dennisguse.opentracks.services.ITrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.settings.SettingsActivity; import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.FileUtils;
import de.dennisguse.opentracks.util.IntentUtils; import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.ListItemUtils; import de.dennisguse.opentracks.util.ListItemUtils;
import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.PreferencesUtils;
@@ -107,8 +118,7 @@ public class TrackListActivity extends AbstractTrackActivity implements ConfirmD
private boolean metricUnits = true; private boolean metricUnits = true;
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT; private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
// Callback when an item is selected in the contextual action mode // Callback when an item is selected in the contextual action mode
private final ContextualActionModeCallback private final ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
contextualActionModeCallback = new ContextualActionModeCallback() {
@Override @Override
public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) { public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) {
@@ -116,7 +126,6 @@ public class TrackListActivity extends AbstractTrackActivity implements ConfirmD
boolean isSingleSelection = ids.length == 1; boolean isSingleSelection = ids.length == 1;
menu.findItem(R.id.list_context_menu_share).setVisible(!isRecording && isSingleSelection); menu.findItem(R.id.list_context_menu_share).setVisible(!isRecording && isSingleSelection);
menu.findItem(R.id.list_context_menu_show_on_map).setVisible(false);
menu.findItem(R.id.list_context_menu_edit).setVisible(isSingleSelection); menu.findItem(R.id.list_context_menu_edit).setVisible(isSingleSelection);
menu.findItem(R.id.list_context_menu_select_all).setVisible(showSelectAll); menu.findItem(R.id.list_context_menu_select_all).setVisible(showSelectAll);
} }
@@ -128,7 +137,7 @@ public class TrackListActivity extends AbstractTrackActivity implements ConfirmD
}; };
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT; private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
/* /*
* Note that sharedPreferenceChangeListenr cannot be an anonymous inner class. * Note that sharedPreferenceChangeListener cannot be an anonymous inner class.
* Anonymous inner class will get garbage collected. * Anonymous inner class will get garbage collected.
*/ */
private final OnSharedPreferenceChangeListener private final OnSharedPreferenceChangeListener
@@ -556,6 +565,59 @@ public class TrackListActivity extends AbstractTrackActivity implements ConfirmD
bindChangedCallback.run(); bindChangedCallback.run();
} }
/**
* Save tracks in one file and send an intent to show it with a map application.
* TODO: Exported file is not deleted automatically.
*
* @param trackIds
*/
private void showOnExternalMap(long[] trackIds) {
if (trackIds.length == 0) {
return;
}
Track[] tracks = new Track[trackIds.length];
for (int i = 0; i < trackIds.length; i++) {
tracks[i] = contentProviderUtils.getTrack(trackIds[i]);
}
TrackFileFormat trackFileFormat = TrackFileFormat.KML;
TrackExporter trackExporter = new FileTrackExporter(contentProviderUtils, tracks,
trackFileFormat.newTrackWriter(this, tracks.length > 1), null);
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;
}
String fileName = FileUtils.buildUniqueFileName(directory, tracks[0].getName(), trackFileFormat.getExtension());
File file = new File(directory, fileName);
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
if (trackExporter.writeTrack(fileOutputStream)) {
Uri fileUri = FileProvider.getUriForFile(this, FileUtils.FILEPROVIDER, file);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(fileUri, "application/vnd.google-earth.kml+xml");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
} else {
if (!file.delete()) {
Log.d(TAG, "Unable to delete file");
}
Log.e(TAG, "Unable to export track");
}
} 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);
}
}
/** /**
* Handles a context item selection. * Handles a context item selection.
* *
@@ -565,6 +627,9 @@ public class TrackListActivity extends AbstractTrackActivity implements ConfirmD
*/ */
private boolean handleContextItem(int itemId, long[] trackIds) { private boolean handleContextItem(int itemId, long[] trackIds) {
switch (itemId) { switch (itemId) {
case R.id.list_context_menu_show_on_map:
showOnExternalMap(trackIds);
return true;
case R.id.list_context_menu_share: case R.id.list_context_menu_share:
//TODO //TODO
Log.e(TAG, "Not implemented"); Log.e(TAG, "Not implemented");
@@ -41,6 +41,7 @@ import de.dennisguse.opentracks.util.SystemUtils;
* *
* @author Jimmy Shih * @author Jimmy Shih
*/ */
//TODO Make independent from ExportActivity?
public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> { public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private static final String TAG = SaveAsyncTask.class.getSimpleName(); private static final String TAG = SaveAsyncTask.class.getSimpleName();
@@ -144,7 +145,7 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
} }
/** /**
* Saves tracks to one file. * Saves tracks to one file (uses first track to determine the filename).
* *
* @param tracks the tracks * @param tracks the tracks
*/ */
@@ -153,7 +154,6 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
return false; return false;
} }
Track track = tracks[0];
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, tracks, FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, tracks,
trackFileFormat.newTrackWriter(context, tracks.length > 1), trackFileFormat.newTrackWriter(context, tracks.length > 1),
new TrackExporterListener() { new TrackExporterListener() {
@@ -169,6 +169,7 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
String extension = useKmz ? KmzTrackExporter.KMZ_EXTENSION : trackFileFormat.getExtension(); String extension = useKmz ? KmzTrackExporter.KMZ_EXTENSION : trackFileFormat.getExtension();
TrackExporter trackExporter = useKmz ? new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks) : fileTrackExporter; TrackExporter trackExporter = useKmz ? new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks) : fileTrackExporter;
Track track = tracks[0];
String fileName = FileUtils.buildUniqueFileName(directory, track.getName(), extension); String fileName = FileUtils.buildUniqueFileName(directory, track.getName(), extension);
File file = new File(directory, fileName); File file = new File(directory, fileName);