Use same thread to export track

This commit is contained in:
Jimmy Shih
2013-09-05 13:34:11 -07:00
parent 429ebdbf3a
commit 9ced32f2df
8 changed files with 53 additions and 122 deletions
@@ -1,68 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file.export;
import android.util.Log;
import java.io.IOException;
import java.io.OutputStream;
/**
* Abstract class for {@link TrackExporter}.
*
* @author Jimmy Shih
*/
abstract class AbstractTrackExporter implements TrackExporter {
private static final String TAG = AbstractTrackExporter.class.getSimpleName();
private Thread writeThread;
private boolean success = false;
@Override
public void writeTrack(final OutputStream outputStream) {
writeThread = new Thread() {
@Override
public void run() {
try {
performWrite(outputStream);
success = true;
} catch (InterruptedException e) {
Log.e(TAG, "Unable to perform write", e);
success = false;
} catch (IOException e) {
Log.e(TAG, "Unable to perform write", e);
success = false;
}
}
};
writeThread.start();
try {
writeThread.join();
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while waiting for write thread to finish", e);
success = false;
}
}
@Override
public boolean isSuccess() {
return success;
}
abstract void performWrite(OutputStream outputStream) throws InterruptedException, IOException;
}
@@ -29,6 +29,7 @@ import com.google.common.annotations.VisibleForTesting;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.location.Location; import android.location.Location;
import android.util.Log;
import java.io.OutputStream; import java.io.OutputStream;
@@ -38,7 +39,9 @@ import java.io.OutputStream;
* @author Sandor Dornbush * @author Sandor Dornbush
* @author Rodrigo Damazio * @author Rodrigo Damazio
*/ */
public class FileTrackExporter extends AbstractTrackExporter { public class FileTrackExporter implements TrackExporter {
private static final String TAG = FileTrackExporter.class.getSimpleName();
private final MyTracksProviderUtils myTracksProviderUtils; private final MyTracksProviderUtils myTracksProviderUtils;
private final Track[] tracks; private final Track[] tracks;
@@ -71,17 +74,23 @@ public class FileTrackExporter extends AbstractTrackExporter {
} }
@Override @Override
void performWrite(OutputStream outputStream) throws InterruptedException { public boolean writeTrack(OutputStream outputStream) {
trackWriter.prepare(outputStream); try {
trackWriter.writeHeader(tracks[0]); trackWriter.prepare(outputStream);
long startTime = tracks[0].getTripStatistics().getStartTime(); trackWriter.writeHeader(tracks[0]);
for (int i = 0; i < tracks.length; i++) { long startTime = tracks[0].getTripStatistics().getStartTime();
writeWaypoints(tracks[i]); for (int i = 0; i < tracks.length; i++) {
long offset = tracks[i].getTripStatistics().getStartTime() - startTime; writeWaypoints(tracks[i]);
writeLocations(tracks[i], offset); long offset = tracks[i].getTripStatistics().getStartTime() - startTime;
writeLocations(tracks[i], offset);
}
trackWriter.writeFooter();
trackWriter.close();
return true;
} catch (InterruptedException e) {
Log.e(TAG, "Thread interrupted", e);
return false;
} }
trackWriter.writeFooter();
trackWriter.close();
} }
/** /**
@@ -22,6 +22,7 @@ import com.google.android.apps.mytracks.content.Waypoint;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.util.Log;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@@ -35,11 +36,13 @@ import java.util.zip.ZipOutputStream;
* *
* @author Jimmy Shih * @author Jimmy Shih
*/ */
public class KmzTrackExporter extends AbstractTrackExporter { public class KmzTrackExporter implements TrackExporter {
public static final String KMZ_EXTENSION = "kmz"; public static final String KMZ_EXTENSION = "kmz";
public static final String KMZ_IMAGES_DIR = "images"; public static final String KMZ_IMAGES_DIR = "images";
public static final String KMZ_KML_FILE = "doc.kml"; public static final String KMZ_KML_FILE = "doc.kml";
private static final String TAG = KmzTrackExporter.class.getSimpleName();
private static final int BUFFER_SIZE = 4096; private static final int BUFFER_SIZE = 4096;
private final MyTracksProviderUtils myTracksProviderUtils; private final MyTracksProviderUtils myTracksProviderUtils;
@@ -61,12 +64,7 @@ public class KmzTrackExporter extends AbstractTrackExporter {
} }
@Override @Override
public boolean isSuccess() { public boolean writeTrack(OutputStream outputStream) {
return fileTrackExporter.isSuccess() && super.isSuccess();
}
@Override
void performWrite(OutputStream outputStream) throws InterruptedException, IOException {
ZipOutputStream zipOutputStream = null; ZipOutputStream zipOutputStream = null;
try { try {
zipOutputStream = new ZipOutputStream(outputStream); zipOutputStream = new ZipOutputStream(outputStream);
@@ -75,17 +73,29 @@ public class KmzTrackExporter extends AbstractTrackExporter {
ZipEntry zipEntry = new ZipEntry(KMZ_KML_FILE); ZipEntry zipEntry = new ZipEntry(KMZ_KML_FILE);
zipOutputStream.putNextEntry(zipEntry); zipOutputStream.putNextEntry(zipEntry);
fileTrackExporter.writeTrack(zipOutputStream); boolean success = fileTrackExporter.writeTrack(zipOutputStream);
zipOutputStream.closeEntry(); zipOutputStream.closeEntry();
if (!fileTrackExporter.isSuccess()) { if (!success) {
throw new IOException(); Log.e(TAG, "Unable to write kml in kmz");
return false;
} }
// Add photos // Add photos
addImages(zipOutputStream); addImages(zipOutputStream);
return true;
} catch (InterruptedException e) {
Log.e(TAG, "Unable to write track", e);
return false;
} catch (IOException e) {
Log.e(TAG, "Unable to write track", e);
return false;
} finally { } finally {
if (zipOutputStream != null) { if (zipOutputStream != null) {
zipOutputStream.close(); try {
zipOutputStream.close();
} catch (IOException e) {
Log.e(TAG, "Unable to close zip input stream", e);;
}
} }
} }
} }
@@ -215,15 +215,14 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
FileOutputStream fileOutputStream = null; FileOutputStream fileOutputStream = null;
try { try {
fileOutputStream = new FileOutputStream(file); fileOutputStream = new FileOutputStream(file);
trackExporter.writeTrack(fileOutputStream); if (trackExporter.writeTrack(fileOutputStream)) {
if (trackExporter.isSuccess()) {
savedPath = file.getAbsolutePath(); savedPath = file.getAbsolutePath();
return true; return true;
} else { } else {
if (!file.delete()) { if (!file.delete()) {
Log.w(TAG, "Failed to delete file " + file.getAbsolutePath()); Log.d(TAG, "Unable to delete file");
} }
Log.e(TAG, "Unable to export track");
return false; return false;
} }
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
@@ -24,17 +24,11 @@ import java.io.OutputStream;
* @author Jimmy Shih * @author Jimmy Shih
*/ */
public interface TrackExporter { public interface TrackExporter {
/** /**
* Write track to an output stream * Write track to an output stream
* *
* @param outputStream the output stream * @param outputStream the output stream
*/ */
void writeTrack(OutputStream outputStream); boolean writeTrack(OutputStream outputStream);
/**
* Returns true if {@link #writeTrack(OutputStream)} completed successfully.
*/
boolean isSuccess();
} }
@@ -447,8 +447,7 @@ public class SyncUtils {
FileOutputStream fileOutputStream = null; FileOutputStream fileOutputStream = null;
try { try {
fileOutputStream = new FileOutputStream(file); fileOutputStream = new FileOutputStream(file);
fileTrackExporter.writeTrack(fileOutputStream); if (fileTrackExporter.writeTrack(fileOutputStream)) {
if (fileTrackExporter.isSuccess()) {
return file; return file;
} else { } else {
if (!file.delete()) { if (!file.delete()) {
@@ -65,11 +65,6 @@ public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>" + getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
+ getTrackPoint(0, null) + getTrackPoint(1, null) + "</trkseg><trkseg>" + getTrackPoint(0, null) + getTrackPoint(1, null) + "</trkseg><trkseg>"
+ getTrackPoint(2, null) + getTrackPoint(3, null) + "</trkseg></trk></gpx>"; + getTrackPoint(2, null) + getTrackPoint(3, null) + "</trkseg></trk></gpx>";
private static final String VALID_TWO_TRACKS_GPX = "<gpx><trk>"
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
+ getTrackPoint(0, TRACK_TIME_0) + "</trkseg></trk><trk>"
+ getNameAndDescription(TRACK_NAME_1, TRACK_DESCRIPTION_1) + "<trkseg>"
+ getTrackPoint(1, TRACK_TIME_1) + "</trkseg></trk></gpx>";
private static final String INVALID_XML_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.substring( private static final String INVALID_XML_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.substring(
0, VALID_ONE_TRACK_ONE_SEGMENT_GPX.length() - 50); 0, VALID_ONE_TRACK_ONE_SEGMENT_GPX.length() - 50);
@@ -7,9 +7,6 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory; import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.file.export.FileTrackExporter;
import com.google.android.apps.mytracks.io.file.export.TrackExporterListener;
import com.google.android.apps.mytracks.io.file.export.TrackWriter;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext; import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory; import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
@@ -101,9 +98,7 @@ public class FileTrackExporterTest extends AndroidTestCase {
trackWriter.writeFooter(); trackWriter.writeFooter();
mocksControl.replay(); mocksControl.replay();
fileTrackExporter.writeTrack(outputStream); assertTrue(fileTrackExporter.writeTrack(outputStream));
assertTrue(fileTrackExporter.isSuccess());
mocksControl.verify(); mocksControl.verify();
} }
@@ -132,9 +127,8 @@ public class FileTrackExporterTest extends AndroidTestCase {
trackWriter.writeFooter(); trackWriter.writeFooter();
mocksControl.replay(); mocksControl.replay();
fileTrackExporter.writeTrack(outputStream);
assertTrue(fileTrackExporter.writeTrack(outputStream));
assertTrue(fileTrackExporter.isSuccess());
mocksControl.verify(); mocksControl.verify();
} }
@@ -196,9 +190,8 @@ public class FileTrackExporterTest extends AndroidTestCase {
trackWriter.writeFooter(); trackWriter.writeFooter();
mocksControl.replay(); mocksControl.replay();
fileTrackExporter.writeTrack(outputStream);
assertTrue(fileTrackExporter.writeTrack(outputStream));
assertTrue(fileTrackExporter.isSuccess());
mocksControl.verify(); mocksControl.verify();
} }