diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml index 8d7c37b0f..b7afaee25 100644 --- a/MyTracks/res/values/strings.xml +++ b/MyTracks/res/values/strings.xml @@ -45,6 +45,7 @@ limitations under the License. File does not have a valid GPX format. An error occurred. Please try again. Track does not exist. + The operation was cancelled. This file is too big (must be less than 500 KB). Aborting. Unable to insert marker. No location fix available. diff --git a/MyTracks/src/com/google/android/apps/mytracks/WriteProgressController.java b/MyTracks/src/com/google/android/apps/mytracks/WriteProgressController.java index 514f2fc02..3f0356756 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/WriteProgressController.java +++ b/MyTracks/src/com/google/android/apps/mytracks/WriteProgressController.java @@ -20,6 +20,7 @@ import com.google.android.maps.mytracks.R; import android.app.Activity; import android.app.ProgressDialog; +import android.content.DialogInterface; /** * Given a {@link TrackWriter}, this class manages the process of writing the @@ -66,6 +67,7 @@ class WriteProgressController { dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); dialog.setMessage(activity.getString(R.string.write_progress_message)); dialog.setIndeterminate(true); + dialog.setOnCancelListener(dialogCancelListener); writer.setOnCompletionListener(writerCompleteListener); writer.setOnWriteListener(writerWriteListener); @@ -87,6 +89,14 @@ class WriteProgressController { return dialog; } + private final DialogInterface.OnCancelListener dialogCancelListener = + new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + writer.stopWriteTrack(); + } + }; + private final TrackWriter.OnCompletionListener writerCompleteListener = new TrackWriter.OnCompletionListener() { @Override diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackFormatWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackFormatWriter.java index 11f93079c..0b7101c6f 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackFormatWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackFormatWriter.java @@ -1,12 +1,12 @@ /* * Copyright 2010 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 @@ -54,7 +54,7 @@ public interface TrackFormatWriter { void prepare(Track track, OutputStream out); /** - * @return The file extentsion (i.e. gpx, kml, ...) + * @return The file extension (i.e. gpx, kml, ...) */ String getExtension(); @@ -77,7 +77,7 @@ public interface TrackFormatWriter { * * @param location the location to write */ - void writeLocation(Location location); + void writeLocation(Location location) throws InterruptedException; /** * Write a way point. diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java index 411ae5061..bace24d33 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java @@ -75,6 +75,11 @@ public interface TrackWriter { */ void writeTrack(); + /** + * Stop any in-progress writes + */ + void stopWriteTrack(); + /** * Returns true if the write completed successfully. */ diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java index 5e0adc968..d74a9c8f4 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java @@ -57,6 +57,7 @@ class TrackWriterImpl implements TrackWriter { private File file = null; private OnCompletionListener onCompletionListener; private OnWriteListener onWriteListener; + private Thread writeThread; TrackWriterImpl(Context context, MyTracksProviderUtils providerUtils, Track track, TrackFormatWriter writer) { @@ -89,28 +90,60 @@ class TrackWriterImpl implements TrackWriter { @Override public void writeTrackAsync() { - Thread t = new Thread() { + writeThread = new Thread() { @Override public void run() { - writeTrack(); + doWriteTrack(); } }; - t.start(); + writeThread.start(); } @Override public void writeTrack() { + writeTrackAsync(); + try { + writeThread.join(); + } catch (InterruptedException e) { + Log.e(Constants.TAG, "Interrupted waiting for write to complete", e); + } + } + + private void doWriteTrack() { // Open the input and output success = false; errorMessage = R.string.error_track_does_not_exist; if (track != null) { if (openFile()) { - writeDocument(); + try { + writeDocument(); + } catch (InterruptedException e) { + Log.i(Constants.TAG, "The track write was interrupted"); + if (file != null) { + file.delete(); + } + success = false; + errorMessage = R.string.error_operation_cancelled; + } } } finished(); } + public void stopWriteTrack() { + if (writeThread != null && writeThread.isAlive()) { + Log.i(Constants.TAG, "Attempting to stop track write"); + writeThread.interrupt(); + + try { + writeThread.join(); + Log.i(Constants.TAG, "Track write stopped"); + } catch (InterruptedException e) { + Log.e(Constants.TAG, "Failed to wait for writer to stop", e); + } + } + } + @Override public int getErrorMessage() { return errorMessage; @@ -253,7 +286,7 @@ class TrackWriterImpl implements TrackWriter { /** * Does the actual work of writing the track to the now open file. */ - void writeDocument() { + void writeDocument() throws InterruptedException { Log.d(Constants.TAG, "Started writing track."); writer.writeHeader(); writeWaypoints(track.getId()); @@ -265,7 +298,7 @@ class TrackWriterImpl implements TrackWriter { errorMessage = R.string.io_write_finished; } - private void writeLocations() { + private void writeLocations() throws InterruptedException { boolean wroteFirst = false; boolean segmentOpen = false; boolean isLastValid = false; @@ -303,6 +336,9 @@ class TrackWriterImpl implements TrackWriter { int pointNumber = 0; while (it.hasNext()) { Location loc = it.next(); + if (Thread.interrupted()) { + throw new InterruptedException(); + } pointNumber++; diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/MockTrackWriter.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/MockTrackWriter.java index c5fbb18a3..813d42a52 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/MockTrackWriter.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/MockTrackWriter.java @@ -59,6 +59,11 @@ public class MockTrackWriter implements TrackWriter { throw new UnsupportedOperationException("not implemented"); } + @Override + public void stopWriteTrack() { + throw new UnsupportedOperationException("not implemented"); + } + @Override public boolean wasSuccess() { return false; diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackFormatWriterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackFormatWriterTest.java index 8c265bc26..6af065c5d 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackFormatWriterTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackFormatWriterTest.java @@ -5,18 +5,9 @@ import com.google.android.apps.mytracks.content.MyTracksLocation; import com.google.android.apps.mytracks.content.Sensor; import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Waypoint; -import com.google.android.apps.mytracks.io.file.TrackFormatWriter; import android.test.AndroidTestCase; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -29,6 +20,14 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + /** * Base class for track format writer tests, which sets up a fake track and * gives auxiliary methods for verifying XML output. @@ -105,9 +104,9 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase { * track in {@link #track}. * * @param writer the writer to write to - * @return the written contents + * @return the written contents */ - protected String writeTrack(TrackFormatWriter writer) { + protected String writeTrack(TrackFormatWriter writer) throws Exception { OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE); writer.prepare(track, output); writer.writeHeader(); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java index 1f74dd500..7ec10b12a 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java @@ -9,10 +9,9 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory; import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Waypoint; -import com.google.android.apps.mytracks.io.file.TrackFormatWriter; -import com.google.android.apps.mytracks.io.file.TrackWriterImpl; import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext; import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory; +import com.google.android.maps.mytracks.R; import android.content.Context; import android.location.Location; @@ -25,6 +24,7 @@ import java.io.FileNotFoundException; import java.io.OutputStream; import org.easymock.EasyMock; +import org.easymock.IAnswer; import org.easymock.IArgumentMatcher; import org.easymock.IMocksControl; @@ -180,6 +180,43 @@ public class TrackWriterTest extends AndroidTestCase { mocksControl.verify(); } + public void testWriteTrack_cancelled() throws Exception { + final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + writer = new OpenFileTrackWriter( + getContext(), providerUtils, track, formatWriter, stream, true); + + formatWriter.prepare(track, stream); + + final Location[] locs = { + new Location("fake0"), + new Location("fake1"), + }; + fillLocations(locs); + assertEquals(locs.length, providerUtils.bulkInsertTrackPoints(locs, locs.length, TRACK_ID)); + + formatWriter.writeHeader(); + formatWriter.writeBeginTrack(locEq(locs[0])); + formatWriter.writeOpenSegment(); + + formatWriter.writeLocation(locEq(locs[0])); + //EasyMock.expectLastCall().andThrow(new InterruptedException()); + EasyMock.expectLastCall().andAnswer(new IAnswer() { + @Override + public Object answer() throws Throwable { + throw new InterruptedException(); + } + }); + + mocksControl.replay(); + + writer.writeTrack(); + + mocksControl.verify(); + + assertFalse(writer.wasSuccess()); + assertEquals(R.string.error_operation_cancelled, writer.getErrorMessage()); + } + public void testWriteTrack_openFails() { writer = new WriteTracksTrackWriter(getContext(), providerUtils, track, formatWriter, false); @@ -229,7 +266,7 @@ public class TrackWriterTest extends AndroidTestCase { mocksControl.verify(); } - public void testWriteDocument_emptyTrack() { + public void testWriteDocument_emptyTrack() throws Exception { writer = new TrackWriterImpl(getContext(), providerUtils, track, formatWriter); // Set expected mock behavior @@ -244,7 +281,7 @@ public class TrackWriterTest extends AndroidTestCase { mocksControl.verify(); } - public void testWriteDocument() { + public void testWriteDocument() throws Exception { writer = new TrackWriterImpl(getContext(), providerUtils, track, formatWriter); final Location[] locs = {