();
+
+ boolean result = trixWrapper.runQuery(new QueryFunction() {
+ @Override
+ public void query(GDataServiceClient client)
+ throws AuthenticationException, IOException, ParseException {
+ String uri = String.format(DOCS_WORKSHEETS_URL_FORMAT, spreadsheetId);
+ GDataParser sheetParser =
+ ((SpreadsheetsClient) client).getParserForWorksheetsFeed(uri,
+ trixWrapper.getAuthManager().getAuthToken());
+ sheetParser.init();
+ if (!sheetParser.hasMoreData()) {
+ Log.i(MyTracksConstants.TAG, "Found no worksheets");
+ return;
+ }
+
+ // Grab the first worksheet.
+ WorksheetEntry worksheetEntry =
+ (WorksheetEntry) sheetParser.readNextEntry(new WorksheetEntry());
+
+ int lastSlash = worksheetEntry.getId().lastIndexOf('/');
+ idSaver.set(worksheetEntry.getId().substring(lastSlash + 1));
+ }
+ });
+
+ if (!result) {
+ throw newIOException(trixWrapper, "Failed to retrieve worksheet ID.");
+ }
+
+ return idSaver.get();
+ }
+
+ /**
+ * Add a row to a worksheet containing the stats for a given track.
+ *
+ * @param context The context associated with this request.
+ * @param trixAuth The GData authorization for the spreadsheet service.
+ * @param spreadsheetId The spreadsheet to be modified.
+ * @param worksheetId The worksheet to be modified.
+ * @param track The track whose stats are to be written.
+ * @param metricUnits True if metric units are to be used. If false,
+ * imperial units will be used.
+ * @throws IOException If an error occurs while updating the worksheet.
+ */
+ public void addTrackRow(Context context, AuthManager trixAuth,
+ String spreadsheetId, String worksheetId, Track track,
+ boolean metricUnits) throws IOException {
+
+ String worksheetUri = String.format(DOCS_SPREADSHEET_URL_FORMAT,
+ spreadsheetId, worksheetId);
+ TripStatistics stats = track.getStatistics();
+
+ String distanceUnit = context.getString(metricUnits ?
+ R.string.kilometer : R.string.mile);
+ String speedUnit = context.getString(metricUnits ?
+ R.string.kilometer_per_hour : R.string.mile_per_hour);
+ String elevationUnit = context.getString(metricUnits ?
+ R.string.meter : R.string.feet);
+
+ // Prepare the Post-Text we are going to send.
+ DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
+ .append("name", track.getName())
+ .append("description", track.getDescription())
+ .append("date", String.format("%tc", stats.getStartTime()))
+ .append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
+ stats.getTotalTime()))
+ .append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
+ stats.getMovingTime()))
+ .appendLargeUnits("distance", stats.getTotalDistance() / 1000)
+ .append("distanceunit", distanceUnit)
+ .appendLargeUnits("averagespeed", stats.getAverageSpeed() * 3.6)
+ .appendLargeUnits("averagemovingspeed",
+ stats.getAverageMovingSpeed() * 3.6)
+ .appendLargeUnits("maxspeed", stats.getMaxSpeed() * 3.6)
+ .append("speedunit", speedUnit)
+ .appendSmallUnits("elevationgain", stats.getTotalElevationGain())
+ .appendSmallUnits("minelevation", stats.getMinElevation())
+ .appendSmallUnits("maxelevation", stats.getMaxElevation())
+ .append("elevationunit", elevationUnit);
+
+ if (track.getMapId().length() > 0) {
+ tagBuilder.append("map", String.format("%s?msa=0&msid=%s",
+ MyMapsConstants.MAPSHOP_BASE_URL, track.getMapId()));
+ }
+
+ String postText = new StringBuilder()
+ .append("")
+ .append(tagBuilder.build())
+ .append("")
+ .toString();
+
+ Log.i(MyTracksConstants.TAG,
+ "Inserting at: " + spreadsheetId + " => " + worksheetUri);
+
+ Log.i(MyTracksConstants.TAG, postText);
+
+ writeRowData(trixAuth, worksheetUri, postText);
+
+ Log.i(MyTracksConstants.TAG, "Post finished.");
+ }
+
+ /**
+ * Writes spreadsheet row data to the indicated worksheet.
+ *
+ * @param trixAuth The GData authorization for the spreadsheet service.
+ * @param worksheetUri The URI of the worksheet to be altered.
+ * @param postText The XML tags describing the change to be made.
+ * @throws IOException Thrown if an error occurs during the write.
+ */
+ protected void writeRowData(AuthManager trixAuth, String worksheetUri,
+ String postText) throws IOException {
+ // No need for a wrapper because we know that the authorization was good
+ // enough to get this far.
+ URL url = new URL(worksheetUri);
+ URLConnection conn = url.openConnection();
+ conn.addRequestProperty(CONTENT_TYPE_PARAM, ATOM_FEED_MIME_TYPE);
+ conn.addRequestProperty("Authorization",
+ "GoogleLogin auth=" + trixAuth.getAuthToken());
+ conn.setDoOutput(true);
+ OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
+ wr.write(postText);
+ wr.flush();
+
+ // Get the response.
+ // TODO: Should we parse the response, rather than simply throwing it away?
+ BufferedReader rd =
+ new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ String line;
+ while ((line = rd.readLine()) != null) {
+ // Process line.
+ Log.i(MyTracksConstants.TAG, "r: " + line);
+ }
+ wr.close();
+ rd.close();
+ }
+
+ private static IOException newIOException(GDataWrapper wrapper,
+ String message) {
+ return new IOException(String.format("%s: %d: %s", message,
+ wrapper.getErrorType(), wrapper.getErrorMessage()));
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/docs/DocsTagBuilder.java b/MyTracks/src/com/google/android/apps/mytracks/io/docs/DocsTagBuilder.java
new file mode 100644
index 000000000..50ab27057
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/docs/DocsTagBuilder.java
@@ -0,0 +1,113 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.apps.mytracks.io.docs;
+
+import com.google.android.apps.mytracks.util.StringUtils;
+import com.google.android.apps.mytracks.util.UnitConversions;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * This class builds a string of XML tags used to talk to Docs using GData.
+ *
+ *
Sample Usage:
+ *
+ *
+ * String tags = new DocsTagBuilder(false)
+ * .append("tagName", "tagValue")
+ * .appendLargeUnits("bigTagName", 1.0)
+ * .build();
+ *
+ *
+ *
results in:
+ *
+ *
+ *
+ *
+ *
+ *
+ * @author Matthew Simmons
+ */
+class DocsTagBuilder {
+ // TODO(simmonmt): These formats aren't I18N-compatible. Not everyone uses
+ // commas for thousands and dots for the decimal point.
+ private static final NumberFormat LARGE_UNIT_FORMAT =
+ new DecimalFormat("#,###,###.00");
+ private static final NumberFormat SMALL_UNIT_FORMAT =
+ new DecimalFormat("###,###");
+
+ protected final boolean metricUnits;
+ protected final StringBuilder stringBuilder;
+
+ /**
+ * @param metricUnits True if metric units are to be used. If false,
+ * imperial units will be used.
+ */
+ DocsTagBuilder(boolean metricUnits) {
+ this.metricUnits = metricUnits;
+ stringBuilder = new StringBuilder();
+ }
+
+ /** Appends a tag containing a string value */
+ DocsTagBuilder append(String name, String value) {
+ appendTag(name, value);
+ return this;
+ }
+
+ /**
+ * Appends a tag containing a numeric value. The value will be formatted
+ * according to the large distance of the specified measurement system (i.e.
+ * kilometers or miles).
+ *
+ * @param name The tag name.
+ * @param d The value to be formatted, in kilometers.
+ */
+ DocsTagBuilder appendLargeUnits(String name, double d) {
+ double value = metricUnits ? d : (d * UnitConversions.KM_TO_MI);
+ appendTag(name, LARGE_UNIT_FORMAT.format(value));
+ return this;
+ }
+
+ /**
+ * Appends a tag containing a numeric value. The value will be formatted
+ * according to the small distance of the specified measurement system (i.e.
+ * meters or feet).
+ *
+ * @param name The tag name.
+ * @param d The value to be formatted, in meters.
+ */
+ DocsTagBuilder appendSmallUnits(String name, double d) {
+ double value = metricUnits ? d : (d * UnitConversions.M_TO_FT);
+ appendTag(name, SMALL_UNIT_FORMAT.format(value));
+ return this;
+ }
+
+ /** Returns a string containing all tags which have been added. */
+ String build() {
+ return stringBuilder.toString();
+ }
+
+ private void appendTag(String name, String value) {
+ stringBuilder.append("")
+ .append(StringUtils.stringAsCData(value))
+ .append("");
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataWrapper.java b/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataWrapper.java
index 97d7cc99e..d45ec9002 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataWrapper.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataWrapper.java
@@ -243,6 +243,10 @@ public class GDataWrapper {
this.auth = auth;
}
+ public AuthManager getAuthManager() {
+ return auth;
+ }
+
public void setRetryOnAuthFailure(boolean retry) {
retryOnAuthFailure = retry;
}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/TrackWriterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/TrackWriterTest.java
index 12542199b..73721214e 100644
--- a/MyTracksTest/src/com/google/android/apps/mytracks/io/TrackWriterTest.java
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/TrackWriterTest.java
@@ -2,31 +2,27 @@
package com.google.android.apps.mytracks.io;
-import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.isA;
-import static org.easymock.EasyMock.leq;
-import static org.easymock.EasyMock.same;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.content.MyTracksProvider;
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.content.MyTracksProviderUtils.Factory;
+import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
import android.content.Context;
-import android.database.MatrixCursor;
import android.location.Location;
-import android.provider.BaseColumns;
import android.test.AndroidTestCase;
+import android.test.RenamingDelegatingContext;
+import android.test.mock.MockContentResolver;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import org.easymock.EasyMock;
-import org.easymock.IAnswer;
import org.easymock.IArgumentMatcher;
import org.easymock.IMocksControl;
@@ -138,12 +134,19 @@ public class TrackWriterTest extends AndroidTestCase {
protected void setUp() throws Exception {
super.setUp();
+ MockContentResolver mockContentResolver = new MockContentResolver();
+ RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
+ getContext(), getContext(), "test.");
+ Context context = new MockContext(mockContentResolver, targetContext);
+ MyTracksProvider provider = new MyTracksProvider();
+ provider.attachInfo(context, null);
+ mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider);
+ setContext(context);
+ providerUtils = MyTracksProviderUtils.Factory.get(context);
+ oldProviderUtilsFactory = TestingProviderUtilsFactory.installWithInstance(providerUtils);
+
mocksControl = EasyMock.createStrictControl();
formatWriter = mocksControl.createMock(TrackFormatWriter.class);
- providerUtils = mocksControl.createMock(MyTracksProviderUtils.class);
- oldProviderUtilsFactory =
- TestingProviderUtilsFactory.installWithInstance(providerUtils);
-
expect(formatWriter.getExtension()).andStubReturn(EXTENSION);
track = new Track();
@@ -225,13 +228,6 @@ public class TrackWriterTest extends AndroidTestCase {
public void testWriteDocument_emptyTrack() {
writer = new TrackWriter(getContext(), providerUtils, track, formatWriter);
- // Don't let it write any waypoints
- expect(providerUtils.getWaypointsCursor(
- TRACK_ID, 0, MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS))
- .andStubReturn(null);
- expect(providerUtils.getLocationsCursor(
- eq(TRACK_ID), leq(0L), leq(0), eq(false))).andStubReturn(null);
-
// Set expected mock behavior
formatWriter.writeHeader();
formatWriter.writeFooter();
@@ -253,7 +249,7 @@ public class TrackWriterTest extends AndroidTestCase {
new Location("fake2"),
new Location("fake3"),
new Location("fake4"),
- new Location("fake5"),
+ new Location("fake5")
};
Waypoint[] wps = { new Waypoint(), new Waypoint(), new Waypoint() };
@@ -262,37 +258,14 @@ public class TrackWriterTest extends AndroidTestCase {
// Make location 3 invalid
locs[2].setLatitude(100);
-
- // Set up cursors
- // We use fake columns since the cursor is only read by the provider utils
- final MatrixCursor locCursor =
- new MatrixCursor(new String[] { BaseColumns._ID }, 6);
- for (int i = 1; i <= 6; i++) {
- locCursor.newRow().add(i);
+
+ assertEquals(locs.length, providerUtils.bulkInsertTrackPoints(locs, locs.length, TRACK_ID));
+ for (int i = 0; i < wps.length; ++i) {
+ Waypoint wpt = wps[i];
+ wpt.setTrackId(TRACK_ID);
+ assertNotNull(providerUtils.insertWaypoint(wpt));
+ wpt.setId(i + 1);
}
- expect(providerUtils.getLocationsCursor(
- eq(TRACK_ID), leq(0L), leq(0), eq(false))).andStubReturn(locCursor);
- providerUtils.fillLocation(same(locCursor), isA(Location.class));
- EasyMock.expectLastCall().andStubAnswer(new IAnswer() {
- @Override
- public Void answer() throws Throwable {
- Location loc = (Location) EasyMock.getCurrentArguments()[1];
- loc.set(locs[locCursor.getPosition()]);
- return null;
- }
- });
-
- MatrixCursor wpCursor =
- new MatrixCursor(new String[] { BaseColumns._ID }, 3);
- wpCursor.newRow().add(1);
- wpCursor.newRow().add(2);
- wpCursor.newRow().add(3);
- expect(providerUtils.getWaypointsCursor(
- eq(TRACK_ID), leq(0L),
- eq(MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS)))
- .andStubReturn(wpCursor);
- expect(providerUtils.createWaypoint(wpCursor))
- .andStubAnswer(stubCursorToArray(wpCursor, wps));
// Begin the track
formatWriter.writeHeader();
@@ -317,8 +290,8 @@ public class TrackWriterTest extends AndroidTestCase {
formatWriter.writeEndTrack(locEq(locs[5]));
// Expect reading/writing of the waypoints (except the first)
- formatWriter.writeWaypoint(wps[1]);
- formatWriter.writeWaypoint(wps[2]);
+ formatWriter.writeWaypoint(wptEq(wps[1]));
+ formatWriter.writeWaypoint(wptEq(wps[2]));
formatWriter.writeFooter();
formatWriter.close();
@@ -330,6 +303,26 @@ public class TrackWriterTest extends AndroidTestCase {
mocksControl.verify();
}
+ private static Waypoint wptEq(final Waypoint wpt) {
+ EasyMock.reportMatcher(new IArgumentMatcher() {
+ @Override
+ public boolean matches(Object wptObj2) {
+ if (wptObj2 == null || wpt == null) return wpt == wptObj2;
+ Waypoint wpt2 = (Waypoint) wptObj2;
+
+ return wpt.getId() == wpt2.getId();
+ }
+
+ @Override
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("wptEq(");
+ buffer.append(wpt);
+ buffer.append(")");
+ }
+ });
+ return null;
+ }
+
private static Location locEq(final Location loc) {
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
@@ -359,23 +352,14 @@ public class TrackWriterTest extends AndroidTestCase {
});
return null;
}
-
- private IAnswer stubCursorToArray(
- final MatrixCursor cursor, final T[] values) {
- return new IAnswer() {
- @Override
- public T answer() throws Throwable {
- return values[cursor.getPosition()];
- }
- };
- }
-
+
private void fillLocations(Location... locs) {
assertTrue(locs.length < 90);
for (int i = 0; i < locs.length; i++) {
Location location = locs[i];
location.setLatitude(i + 1);
location.setLongitude(i + 1);
+ location.setTime(i + 1000);
}
}
}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelperTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelperTest.java
new file mode 100644
index 000000000..b1402c06f
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelperTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.apps.mytracks.io.docs;
+
+import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
+
+import android.content.Context;
+import android.test.mock.MockContext;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+/**
+ * Tests for {@link DocsHelper}, with the exception of
+ * {@link DocsHelper#addTrackRow}, which is in
+ * {@link DocsHelper_AddTrackRowTest}.
+ *
+ * @author Matthew Simmons
+ */
+public class DocsHelperTest extends TestCase {
+ private Context mockContext = new MockContext();
+
+ // TODO(simmonmt): Use AndroidMock to mock this class. We do it the hard
+ // way because use of AndroidMock to mock GDataWrapper triggers a compile
+ // error in an unrelated file. Specifically, it causes a NoClassDefFound
+ // exception for com.google.wireless.gdata2.client.AuthenticationException,
+ // (wrongly) attributed to the first source file in the project. Using the
+ // @UsesMocks(GDataWrapper.class) annotation is enough -- you don't have to
+ // touch AndroidMock at all to get this failure.
+ // The bug is filed with Android Mock as
+ // http://code.google.com/p/android-mock/issues/detail?id=3
+ private class MockGDataWrapper extends GDataWrapper {
+ private final boolean returnValue;
+
+ MockGDataWrapper(boolean returnValue) {
+ this.returnValue = returnValue;
+ }
+
+ @Override
+ public boolean runQuery(QueryFunction queryFunction) {
+ return returnValue;
+ }
+ }
+
+ public void testCreateSpreadsheet_noException() throws Exception {
+ // Our mock GDataWrapper isn't able to affect the return value from
+ // DocsHelper#createSpreadsheet. As such, we're only able to simulate the
+ // case where there weren't any GData errors, but not spreadsheet ID was
+ // actually returned. createSpreadsheet is defined to return null in that
+ // situation.
+ assertNull(new DocsHelper().createSpreadsheet(
+ mockContext, new MockGDataWrapper(true), "sheetName"));
+ }
+
+ public void testCreateSpreadsheet_exception() throws Exception {
+ try {
+ new DocsHelper().createSpreadsheet(
+ mockContext, new MockGDataWrapper(false), "sheetName");
+ fail();
+ } catch (IOException expected) {}
+ }
+
+ public void testRequestSpreadsheetId_noException() throws Exception {
+ assertNull(new DocsHelper().requestSpreadsheetId(
+ new MockGDataWrapper(true), "sheetName"));
+ }
+
+ public void testRequestSpreadsheetId_exception() throws Exception {
+ try {
+ new DocsHelper().requestSpreadsheetId(new MockGDataWrapper(false),
+ "sheetName");
+ fail();
+ } catch (IOException expected) {}
+ }
+
+ public void testGetWorksheetId_noException() throws Exception {
+ assertNull(new DocsHelper().getWorksheetId(new MockGDataWrapper(true),
+ "sheetId"));
+ }
+
+ public void testGetWorksheetId_exception() throws Exception {
+ try {
+ new DocsHelper().getWorksheetId(new MockGDataWrapper(false), "sheetId");
+ fail();
+ } catch (IOException expected) {}
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelper_AddTrackRowTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelper_AddTrackRowTest.java
new file mode 100644
index 000000000..e357605b4
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelper_AddTrackRowTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.apps.mytracks.io.docs;
+
+import com.google.android.apps.mytracks.content.Track;
+import com.google.android.apps.mytracks.io.AuthManager;
+import com.google.android.apps.mytracks.stats.TripStatistics;
+import com.google.android.testing.mocking.AndroidMock;
+import com.google.android.testing.mocking.UsesMocks;
+import com.google.android.maps.mytracks.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.test.mock.MockContext;
+import android.test.mock.MockResources;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+/**
+ * Tests for {@link DocsHelper#addTrackRow}
+ *
+ * @author Matthew Simmons
+ */
+public class DocsHelper_AddTrackRowTest extends TestCase {
+ private static final long TIME = 1288721514000L;
+
+ private static class StringWritingDocsHelper extends DocsHelper {
+ String writtenSheetUri = null;
+ String writtenData = null;
+
+ @Override
+ protected void writeRowData(AuthManager trixAuth, String worksheetUri,
+ String postText) {
+ writtenSheetUri = worksheetUri;
+ writtenData = postText;
+ }
+ }
+
+ public void testAddTrackRow_imperial() throws Exception {
+ StringWritingDocsHelper docsHelper = new StringWritingDocsHelper();
+ addTrackRow(docsHelper, false);
+
+ String expectedData =
+ ""
+ + ""
+ + ""
+ // We format the date here because we can't guarantee/force the timezone
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + "";
+
+ assertEquals(
+ "http://spreadsheets.google.com/feeds/list/ssid/wsid/private/full",
+ docsHelper.writtenSheetUri);
+ assertEquals(expectedData, docsHelper.writtenData);
+ }
+
+ public void testAddTrackRow_metric() throws Exception {
+ StringWritingDocsHelper docsHelper = new StringWritingDocsHelper();
+ addTrackRow(docsHelper, true);
+
+ // The imperial test verifies that the tags come out in the proper order,
+ // and with the proper names. We need only verify that the labels are
+ // correct, and that at least one of the unit-dependent value tags is
+ // correct.
+ assertTrue(docsHelper.writtenData.contains(
+ ""));
+ assertTrue(docsHelper.writtenData.contains(
+ ""));
+ assertTrue(docsHelper.writtenData.contains(
+ ""));
+
+ assertTrue(docsHelper.writtenData.contains(
+ ""));
+ }
+
+ @UsesMocks({AuthManager.class, MockContext.class, MockResources.class,
+ Track.class})
+ /** Adds a row to the spreadsheet, using the provided helper. */
+ private void addTrackRow(DocsHelper docsHelper, boolean useMetric)
+ throws IOException {
+ Resources mockResources = AndroidMock.createMock(MockResources.class);
+
+ if (useMetric) {
+ AndroidMock.expect(mockResources.getString(R.string.kilometer))
+ .andReturn("km");
+ AndroidMock.expect(mockResources.getString(R.string.kilometer_per_hour))
+ .andReturn("kph");
+ AndroidMock.expect(mockResources.getString(R.string.meter))
+ .andReturn("meter");
+ } else {
+ AndroidMock.expect(mockResources.getString(R.string.mile))
+ .andReturn("mile");
+ AndroidMock.expect(mockResources.getString(R.string.mile_per_hour))
+ .andReturn("mph");
+ AndroidMock.expect(mockResources.getString(R.string.feet))
+ .andReturn("feet");
+ }
+ AndroidMock.replay(mockResources);
+
+ Context mockContext = AndroidMock.createMock(MockContext.class);
+ AndroidMock.expect(mockContext.getResources())
+ .andReturn(mockResources).anyTimes();
+ AndroidMock.replay(mockContext);
+
+ AuthManager mockAuthManager = AndroidMock.createMock(AuthManager.class);
+ AndroidMock.replay(mockAuthManager);
+
+ TripStatistics stats = new TripStatistics();
+ stats.setStartTime(TIME);
+ stats.setTotalTime(5000);
+ stats.setMovingTime(4000);
+ stats.setTotalDistance(20000);
+ stats.setMaxSpeed(1500);
+ stats.setTotalElevationGain(6000);
+ stats.setMinElevation(-500);
+ stats.setMaxElevation(550);
+
+ Track track = new Track();
+ track.setName("trackName");
+ track.setDescription("trackDescription");
+ track.setMapId("trackMapId");
+ track.setStatistics(stats);
+
+ docsHelper.addTrackRow(mockContext, mockAuthManager, "ssid", "wsid",
+ track, useMetric);
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsTagBuilderTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsTagBuilderTest.java
new file mode 100644
index 000000000..0145f6a9e
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsTagBuilderTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.apps.mytracks.io.docs;
+
+import junit.framework.TestCase;
+
+/**
+ * This class tests {@link DocsTagBuilder}
+ *
+ * @author Matthew Simmons
+ */
+public class DocsTagBuilderTest extends TestCase {
+ public void testAppend() {
+ assertEquals("",
+ new DocsTagBuilder(false).append("tag", "value").build());
+ }
+
+ public void testMultiAppend() {
+ String actual = new DocsTagBuilder(false)
+ .append("tag1", "value1")
+ .append("tag2", "value2")
+ .build();
+
+ assertEquals(""
+ + "", actual);
+ }
+
+ public void testAppendLargeUnits_imperial() {
+ assertEquals("",
+ new DocsTagBuilder(false).appendLargeUnits("tag", 100.0).build());
+ }
+
+ public void testAppendLargeUnits_metric() {
+ assertEquals("",
+ new DocsTagBuilder(true).appendLargeUnits("tag", 100.0).build());
+ }
+
+ public void testAppendSmallUnits_imperial() {
+ assertEquals("",
+ new DocsTagBuilder(false).appendSmallUnits("tag", 100.0).build());
+ }
+
+ public void testAppendSmallUnits_metric() {
+ assertEquals("",
+ new DocsTagBuilder(true).appendSmallUnits("tag", 100.0).build());
+ }
+}
diff --git a/SignalStrengthSampler/src/com/google/android/apps/mytracks/signalstrength/SignalStrengthService.java b/SignalStrengthSampler/src/com/google/android/apps/mytracks/signalstrength/SignalStrengthService.java
index 210fefe02..8a9cf4cd3 100644
--- a/SignalStrengthSampler/src/com/google/android/apps/mytracks/signalstrength/SignalStrengthService.java
+++ b/SignalStrengthSampler/src/com/google/android/apps/mytracks/signalstrength/SignalStrengthService.java
@@ -19,7 +19,6 @@ import static com.google.android.apps.mytracks.signalstrength.SignalStrengthCons
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsImpl;
-import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.signalstrength.SignalStrengthListener.SignalStrengthCallback;
@@ -56,7 +55,6 @@ public class SignalStrengthService extends Service
private ITrackRecordingService mytracksService;
private long lastSamplingTime;
private long samplingPeriod;
- private MyTracksProviderUtils utils;
@Override
public void onCreate() {
@@ -67,7 +65,6 @@ public class SignalStrengthService extends Service
getString(R.string.mytracks_service_class));
preferences = PreferenceManager.getDefaultSharedPreferences(this);
signalListenerFactory = new SignalStrengthListenerFactory();
- utils = new MyTracksProviderUtilsImpl(this.getContentResolver());
}
@Override