KML/KMZ export and share: add configuration to export with trackdetail without the rest.

Fixed some issues in TRACK_ONLY mode as too much data was exposed.
This commit is contained in:
Dennis Guse
2019-09-15 09:45:31 +02:00
parent afd25363b3
commit 9dd2f7d1c1
6 changed files with 139 additions and 65 deletions
@@ -44,21 +44,28 @@ public class ShareContentProvider extends CustomContentProvider implements ICont
private static final int URI_GPX = 0;
private static final int URI_KML_ONLY = 1;
private static final int URI_KML_WITH_SENSORDATA = 2;
private static final int URI_KMZ_ONLY_TRACK = 3;
private static final int URI_KMZ_WITH_SENSORDATA = 4;
private static final int URI_KMZ_WITH_SENSORDATA_AND_PICTURES = 5;
private static final int URI_KML_WITH_TRACKDETAIL = 2;
private static final int URI_KML_WITH_TRACKDETAIL_SENSORDATA = 3;
private static final int URI_KMZ_ONLY_TRACK = 4;
private static final int URI_KMZ_WITH_TRACKDETAIL = 5;
private static final int URI_KMZ_WITH_TRACKDETAIL_AND_SENSORDATA = 6;
private static final int URI_KMZ_WITH_TRACKDETAIL_SENSORDATA_AND_PICTURES = 7;
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final String TRACKID_DELIMITER = "_";
static {
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KML_ONLY_TRACK.getName() + "/*", URI_KML_ONLY);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KML_WITH_SENSORDATA.getName() + "/*", URI_KML_WITH_SENSORDATA);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_ONLY_TRACK.getName() + "/*", URI_KMZ_ONLY_TRACK);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_WITH_SENSORDATA.getName() + "/*", URI_KMZ_WITH_SENSORDATA);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_WITH_SENSORDATA_AND_PICTURES.getName() + "/*", URI_KMZ_WITH_SENSORDATA_AND_PICTURES);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.GPX.getName() + "/*", URI_GPX);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KML_ONLY_TRACK.getName() + "/*", URI_KML_ONLY);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KML_WITH_TRACKDETAIL.getName() + "/*", URI_KML_WITH_TRACKDETAIL);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.getName() + "/*", URI_KML_WITH_TRACKDETAIL_SENSORDATA);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_ONLY_TRACK.getName() + "/*", URI_KMZ_ONLY_TRACK);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_WITH_TRACKDETAIL.getName() + "/*", URI_KMZ_WITH_TRACKDETAIL);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA.getName() + "/*", URI_KMZ_WITH_TRACKDETAIL_AND_SENSORDATA);
uriMatcher.addURI(ContentProviderUtils.AUTHORITY_PACKAGE, TracksColumns.TABLE_NAME + "/" + TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES.getName() + "/*", URI_KMZ_WITH_TRACKDETAIL_SENSORDATA_AND_PICTURES);
}
public static Pair<Uri, String> createURI(long[] trackIds, @NonNull TrackFileFormat trackFileFormat) {
@@ -118,16 +125,25 @@ public class ShareContentProvider extends CustomContentProvider implements ICont
switch (uriMatcher.match(uri)) {
case URI_GPX:
return TrackFileFormat.GPX;
case URI_KML_ONLY:
return TrackFileFormat.KML_ONLY_TRACK;
case URI_KML_WITH_SENSORDATA:
return TrackFileFormat.KML_WITH_SENSORDATA;
case URI_KMZ_WITH_SENSORDATA:
return TrackFileFormat.KMZ_WITH_SENSORDATA;
case URI_KMZ_WITH_SENSORDATA_AND_PICTURES:
return TrackFileFormat.KMZ_WITH_SENSORDATA_AND_PICTURES;
default: //URI_KMZ_ONLY_TRACK
case URI_KML_WITH_TRACKDETAIL:
return TrackFileFormat.KML_WITH_TRACKDETAIL;
case URI_KML_WITH_TRACKDETAIL_SENSORDATA:
return TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA;
case URI_KMZ_ONLY_TRACK:
return TrackFileFormat.KMZ_ONLY_TRACK;
case URI_KMZ_WITH_TRACKDETAIL:
return TrackFileFormat.KMZ_WITH_TRACKDETAIL;
case URI_KMZ_WITH_TRACKDETAIL_AND_SENSORDATA:
return TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA;
case URI_KMZ_WITH_TRACKDETAIL_SENSORDATA_AND_PICTURES:
return TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES;
default:
throw new RuntimeException("Could not derive TrackFileFormat from Uri " + uri);
}
}
@@ -65,7 +65,7 @@ public class FileTypeDialogFragment extends AbstractDialogFragment {
protected Dialog createDialog() {
int optionId = getArguments().getInt(KEY_OPTION_ID);
final int titleId = getArguments().getInt(KEY_TITLE_ID);
final TrackFileFormat[] trackFileFormats = {TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES, TrackFileFormat.KML_WITH_TRACKDETAILS_AND_SENSORDATA, TrackFileFormat.GPX};
final TrackFileFormat[] trackFileFormats = {TrackFileFormat.KML_WITH_TRACKDETAIL, TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.GPX};
String[] choices = new String[trackFileFormats.length];
for (int i = 0; i < choices.length; i++) {
TrackFileFormat trackFileFormat = trackFileFormats[i];
@@ -35,7 +35,22 @@ public enum TrackFileFormat {
return "kml";
}
},
KML_WITH_SENSORDATA {
KML_WITH_TRACKDETAIL {
@Override
public TrackWriter newTrackWriter(Context context, boolean multiple) {
return new KmlTrackWriter(context, multiple, true, false, false);
}
@Override
public String getMimeType() {
return MIME_KML;
}
public String getExtension() {
return "kml";
}
},
KML_WITH_TRACKDETAIL_AND_SENSORDATA {
@Override
public TrackWriter newTrackWriter(Context context, boolean multiple) {
return new KmlTrackWriter(context, multiple, true, true, false);
@@ -51,13 +66,16 @@ public enum TrackFileFormat {
}
},
KMZ_ONLY_TRACK {
private final static boolean exportPhotos = false;
@Override
public TrackWriter newTrackWriter(Context context, boolean multiple) {
return new KmlTrackWriter(context, multiple, false, false, false);
return new KmlTrackWriter(context, multiple, false, false, exportPhotos);
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener);
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener, exportPhotos);
}
@Override
@@ -69,10 +87,17 @@ public enum TrackFileFormat {
return "kmz";
}
},
KMZ_WITH_SENSORDATA {
KMZ_WITH_TRACKDETAIL {
private final static boolean exportPhotos = false;
@Override
public TrackWriter newTrackWriter(Context context, boolean multiple) {
return new KmlTrackWriter(context, multiple, true, true, false);
return new KmlTrackWriter(context, multiple, true, false, exportPhotos);
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener, exportPhotos);
}
@Override
@@ -80,18 +105,17 @@ public enum TrackFileFormat {
return MIME_KMZ;
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener);
}
public String getExtension() {
return "kmz";
}
},
KMZ_WITH_SENSORDATA_AND_PICTURES {
KMZ_WITH_TRACKDETAIL_AND_SENSORDATA {
private final static boolean exportPhotos = false;
@Override
public TrackWriter newTrackWriter(Context context, boolean multiple) {
return new KmlTrackWriter(context, multiple, true, true, true);
return new KmlTrackWriter(context, multiple, true, true, exportPhotos);
}
@Override
@@ -100,7 +124,29 @@ public enum TrackFileFormat {
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener);
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener, exportPhotos);
}
public String getExtension() {
return "kmz";
}
},
KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES {
private final static boolean exportPhotos = true;
@Override
public TrackWriter newTrackWriter(Context context, boolean multiple) {
return new KmlTrackWriter(context, multiple, true, true, exportPhotos);
}
@Override
public String getMimeType() {
return MIME_KMZ;
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener, exportPhotos);
}
public String getExtension() {
@@ -138,12 +184,12 @@ public enum TrackFileFormat {
*/
public abstract String getMimeType();
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, Track[] tracks, TrackExporterListener trackExporterListener) {
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, Track[] tracks, TrackExporterListener trackExporterListener, boolean exportPhotos) {
ContentProviderUtils contentProviderUtils = ContentProviderUtils.Factory.get(context);
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, trackWriter, tracks, trackExporterListener);
return new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks);
return new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks, exportPhotos);
}
/**
@@ -23,6 +23,7 @@ import android.net.Uri;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.ContentProviderUtils;
@@ -60,16 +61,16 @@ public class KmlTrackWriter implements TrackWriter {
private final Context context;
private final boolean hasMultipleTracks;
private final boolean exportPictures;
private final boolean exportTrackDetails;
private final boolean exportPhotos;
private final boolean exportTrackDetail;
private final boolean exportSensorData;
private final DescriptionGenerator descriptionGenerator;
private final ContentProviderUtils contentProviderUtils;
private PrintWriter printWriter;
private ArrayList<Float> powerList = new ArrayList<>();
private ArrayList<Float> cadenceList = new ArrayList<>();
private ArrayList<Float> heartRateList = new ArrayList<>();
private List<Float> powerList = new ArrayList<>();
private List<Float> cadenceList = new ArrayList<>();
private List<Float> heartRateList = new ArrayList<>();
private boolean hasPower;
private boolean hasCadence;
private boolean hasHeartRate;
@@ -79,16 +80,16 @@ public class KmlTrackWriter implements TrackWriter {
/**
* @param context the context
* @param hasMultipleTracks should encode multiple tracks into one file?
* @param exportPictures should pictures be exported (if true: exports to KMZ)?
* @param exportTrackDetails should detailed information about the track be exported (e.g., title, description, waypoints, timing)?
* @param exportTrackDetail should detailed information about the track be exported (e.g., title, description, waypoints, timing)?
* @param exportSensorData should {@link SensorDataSet} be exported?
* @param exportPhotos should pictures be exported (if true: exports to KMZ)?
*/
public KmlTrackWriter(Context context, boolean hasMultipleTracks, boolean exportTrackDetails, boolean exportSensorData, boolean exportPictures) {
public KmlTrackWriter(Context context, boolean hasMultipleTracks, boolean exportTrackDetail, boolean exportSensorData, boolean exportPhotos) {
this.context = context;
this.hasMultipleTracks = hasMultipleTracks;
this.exportTrackDetails = exportTrackDetails;
this.exportTrackDetail = exportTrackDetail;
this.exportSensorData = exportSensorData;
this.exportPictures = exportPictures;
this.exportPhotos = exportPhotos;
this.descriptionGenerator = new DescriptionGeneratorImpl(context);
this.contentProviderUtils = ContentProviderUtils.Factory.get(context);
}
@@ -117,12 +118,12 @@ public class KmlTrackWriter implements TrackWriter {
printWriter.println("<open>1</open>");
printWriter.println("<visibility>1</visibility>");
if (exportTrackDetails) {
if (exportTrackDetail) {
Track track = tracks[0];
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println("<atom:author><atom:name>" + StringUtils.formatCData(context.getString(R.string.app_name)) + "</atom:name></atom:author>");
}
printWriter.println("<atom:author><atom:name>" + StringUtils.formatCData(context.getString(R.string.app_name)) + "</atom:name></atom:author>");
writeTrackStyle();
writePlacemarkerStyle(START_STYLE, START_ICON, 32, 1);
writePlacemarkerStyle(END_STYLE, END_ICON, 32, 1);
@@ -151,7 +152,7 @@ public class KmlTrackWriter implements TrackWriter {
public void writeBeginWaypoints(Track track) {
if (printWriter != null) {
printWriter.println("<Folder>");
if (exportTrackDetails) {
if (exportTrackDetail) {
printWriter.println("<name>" + StringUtils.formatCData(context.getString(R.string.track_markers, track.getName())) + "</name>");
}
printWriter.println("<open>1</open>");
@@ -167,9 +168,10 @@ public class KmlTrackWriter implements TrackWriter {
@Override
public void writeWaypoint(Waypoint waypoint) {
if (printWriter != null && exportTrackDetails) {
if (printWriter != null && exportTrackDetail) {
String styleName = waypoint.getType() == WaypointType.STATISTICS ? STATISTICS_STYLE : WAYPOINT_STYLE;
if (waypoint.hasPhoto()) {
if (waypoint.hasPhoto() && exportPhotos) {
float heading = getHeading(waypoint.getTrackId(), waypoint.getLocation());
writePhotoOverlay(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(), styleName, waypoint.getLocation(), waypoint.getPhotoUrl(), heading);
} else {
@@ -201,8 +203,12 @@ public class KmlTrackWriter implements TrackWriter {
String name = context.getString(R.string.marker_label_start, track.getName());
writePlacemark(name, "", "", START_STYLE, startLocation);
printWriter.println("<Placemark>");
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println("<description>" + StringUtils.formatCData(track.getDescription()) + "</description>");
if (exportTrackDetail) {
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println("<description>" + StringUtils.formatCData(track.getDescription()) + "</description>");
}
printWriter.println("<styleUrl>#" + TRACK_STYLE + "</styleUrl>");
writeCategory(track.getCategory());
printWriter.println("<gx:MultiTrack>");
@@ -216,9 +222,12 @@ public class KmlTrackWriter implements TrackWriter {
if (printWriter != null) {
printWriter.println("</gx:MultiTrack>");
printWriter.println("</Placemark>");
String name = context.getString(R.string.marker_label_end, track.getName());
String description = descriptionGenerator.generateTrackDescription(track, false);
writePlacemark(name, "", description, END_STYLE, endLocation);
if (exportTrackDetail) {
String name = context.getString(R.string.marker_label_end, track.getName());
String description = descriptionGenerator.generateTrackDescription(track, false);
writePlacemark(name, "", description, END_STYLE, endLocation);
}
}
}
@@ -260,7 +269,7 @@ public class KmlTrackWriter implements TrackWriter {
@Override
public void writeLocation(Location location) {
if (printWriter != null) {
if (exportTrackDetails) {
if (exportTrackDetail) {
printWriter.println("<when>" + getTime(location) + "</when>");
}
@@ -289,7 +298,7 @@ public class KmlTrackWriter implements TrackWriter {
* @param list a list of sensor data
* @param name the name of the sensor data
*/
private void writeSensorData(ArrayList<Float> list, String name) {
private void writeSensorData(List<Float> list, String name) {
printWriter.println("<gx:SimpleArrayData name=\"" + name + "\">");
for (int i = 0; i < list.size(); i++) {
printWriter.println("<gx:value>" + list.get(i) + "</gx:value>");
@@ -307,7 +316,7 @@ public class KmlTrackWriter implements TrackWriter {
* @param location the location
*/
private void writePlacemark(String name, String category, String description, String styleName, Location location) {
if (location != null && exportTrackDetails) {
if (location != null && exportTrackDetail) {
printWriter.println("<Placemark>");
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
printWriter.println("<description>" + StringUtils.formatCData(description) + "</description>");
@@ -333,7 +342,7 @@ public class KmlTrackWriter implements TrackWriter {
* @param heading the heading
*/
private void writePhotoOverlay(String name, String category, String description, String styleName, Location location, String photoUrl, float heading) {
if (location != null && exportTrackDetails) {
if (location != null && exportTrackDetail) {
printWriter.println("<PhotoOverlay>");
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
printWriter.println("<description>" + StringUtils.formatCData(description) + "</description>");
@@ -348,7 +357,7 @@ public class KmlTrackWriter implements TrackWriter {
printWriter.println("<styleUrl>#" + styleName + "</styleUrl>");
writeCategory(category);
if (exportPictures) {
if (exportPhotos) {
printWriter.println("<Icon><href>" + Uri.decode(photoUrl) + "</href></Icon>");
}
@@ -367,12 +376,12 @@ public class KmlTrackWriter implements TrackWriter {
}
/**
* Returns the formatted time of the location; either absolute or relative depending exportTrackDetails.
* Returns the formatted time of the location; either absolute or relative depending exportTrackDetail.
*
* @param location the location
*/
private String getTime(Location location) {
if (exportTrackDetails) {
if (exportTrackDetail) {
return StringUtils.formatDateTimeIso8601(location.getTime());
} else {
return StringUtils.formatDateTimeIso8601(location.getTime() - startLocation.getTime());
@@ -49,20 +49,23 @@ public class KmzTrackExporter implements TrackExporter {
private static final int BUFFER_SIZE = 4096;
private final ContentProviderUtils contentProviderUtils;
private final FileTrackExporter fileTrackExporter;
private final TrackExporter fileTrackExporter;
private final Track[] tracks;
private boolean exportPhotos;
/**
* Constructor.
*
* @param contentProviderUtils the content provider utils
* @param fileTrackExporter the file track exporter
* @param trackExporter the file track exporter
* @param tracks the tracks to export
*/
public KmzTrackExporter(ContentProviderUtils contentProviderUtils, FileTrackExporter fileTrackExporter, Track[] tracks) {
public KmzTrackExporter(ContentProviderUtils contentProviderUtils, TrackExporter trackExporter, Track[] tracks, boolean exportPhotos) {
this.contentProviderUtils = contentProviderUtils;
this.fileTrackExporter = fileTrackExporter;
this.fileTrackExporter = trackExporter;
this.tracks = tracks;
this.exportPhotos = exportPhotos;
}
@Override
@@ -83,7 +86,7 @@ public class KmzTrackExporter implements TrackExporter {
}
// Add photos
addImages(context, zipOutputStream);
if (exportPhotos) addImages(context, zipOutputStream);
return true;
} catch (InterruptedException | IOException e) {
Log.e(TAG, "Unable to write track", e);
@@ -75,7 +75,7 @@ public class IntentUtils {
Track track = ContentProviderUtils.Factory.get(context).getTrack(trackIds[0]);
trackDescription = track == null ? "" : new DescriptionGeneratorImpl(context).generateTrackDescription(track, false);
}
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, TrackFileFormat.KMZ_WITH_SENSORDATA_AND_PICTURES);
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES);
return new Intent(Intent.ACTION_SEND)
.putExtra(Intent.EXTRA_STREAM, uriAndMime.first)
@@ -124,7 +124,7 @@ public class IntentUtils {
return;
}
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, TrackFileFormat.KMZ_ONLY_TRACK);
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, TrackFileFormat.KMZ_WITH_TRACKDETAIL);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(uriAndMime.first, uriAndMime.second);