Update GpxImporter to support tracks with pauses.

This commit is contained in:
Jimmy Shih
2012-08-28 17:44:40 -07:00
commit 2f6e36a8bc
695 changed files with 65119 additions and 0 deletions
@@ -0,0 +1,52 @@
/*
* Copyright 2012 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.sendtogoogle.AbstractSendActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import android.content.Intent;
/**
* An activity to send a track to Google Docs.
*
* @author Jimmy Shih
*/
public class SendDocsActivity extends AbstractSendActivity {
@Override
protected AbstractSendAsyncTask createAsyncTask() {
return new SendDocsAsyncTask(this, sendRequest.getTrackId(), sendRequest.getAccount());
}
@Override
protected String getServiceName() {
return getString(R.string.send_google_docs);
}
@Override
protected void startNextActivity(boolean success, boolean isCancel) {
sendRequest.setDocsSuccess(success);
Intent intent = IntentUtils.newIntent(this, UploadResultActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
finish();
}
}
@@ -0,0 +1,324 @@
/*
* Copyright 2012 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.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
import com.google.android.apps.mytracks.io.gdata.docs.DocumentsClient;
import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient;
import com.google.android.apps.mytracks.io.gdata.docs.XmlDocsGDataParserFactory;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.common.gdata.AndroidXmlParserFactory;
import com.google.android.maps.mytracks.R;
import com.google.wireless.gdata.client.GDataClient;
import com.google.wireless.gdata.client.HttpException;
import com.google.wireless.gdata.parser.ParseException;
import com.google.wireless.gdata2.client.AuthenticationException;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.util.Log;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/**
* AsyncTask to send a track to Google Docs.
*
* @author Jimmy Shih
*/
public class SendDocsAsyncTask extends AbstractSendAsyncTask {
private static final int PROGRESS_GET_SPREADSHEET_ID = 0;
private static final int PROGRESS_CREATE_SPREADSHEET = 25;
private static final int PROGRESS_GET_WORKSHEET_ID = 50;
private static final int PROGRESS_ADD_TRACK_INFO = 75;
private static final int PROGRESS_COMPLETE = 100;
private static final String TAG = SendDocsAsyncTask.class.getSimpleName();
private final long trackId;
private final Account account;
private final Context context;
private final MyTracksProviderUtils myTracksProviderUtils;
private final GDataClient gDataClient;
private final DocumentsClient documentsClient;
private final SpreadsheetsClient spreadsheetsClient;
// The following variables are for per upload states
private String documentsAuthToken;
private String spreadsheetsAuthToken;
private String spreadsheetId;
private String worksheetId;
public SendDocsAsyncTask(SendDocsActivity activity, long trackId, Account account) {
super(activity);
this.trackId = trackId;
this.account = account;
context = activity.getApplicationContext();
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
gDataClient = GDataClientFactory.getGDataClient(context);
documentsClient = new DocumentsClient(
gDataClient, new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
spreadsheetsClient = new SpreadsheetsClient(
gDataClient, new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
}
@Override
protected void closeConnection() {
if (gDataClient != null) {
gDataClient.close();
}
}
@Override
protected void saveResult() {
// No action for Google Docs
}
@Override
protected boolean performTask() {
// Reset the per upload states
documentsAuthToken = null;
spreadsheetsAuthToken = null;
spreadsheetId = null;
worksheetId = null;
try {
documentsAuthToken = AccountManager.get(context).blockingGetAuthToken(
account, documentsClient.getServiceName(), false);
spreadsheetsAuthToken = AccountManager.get(context).blockingGetAuthToken(
account, spreadsheetsClient.getServiceName(), false);
} catch (OperationCanceledException e) {
Log.d(TAG, "Unable to get auth token", e);
return retryTask();
} catch (AuthenticatorException e) {
Log.d(TAG, "Unable to get auth token", e);
return retryTask();
} catch (IOException e) {
Log.d(TAG, "Unable to get auth token", e);
return retryTask();
}
Track track = myTracksProviderUtils.getTrack(trackId);
if (track == null) {
Log.d(TAG, "No track for " + trackId);
return false;
}
String title = context.getString(R.string.my_tracks_app_name);
if (track.getCategory() != null && !track.getCategory().equals("")) {
title += "-" + track.getCategory();
}
try {
title = URLEncoder.encode(title, "UTF-8");
title = title.replace('+', ' ');
} catch (UnsupportedEncodingException e) {
Log.d(TAG, "No UTF-8 encoding", e);
return false;
}
// Get the spreadsheet ID
publishProgress(PROGRESS_GET_SPREADSHEET_ID);
if (!fetchSpreadSheetId(title, false)) {
return retryTask();
}
// Create a new spreadsheet if necessary
publishProgress(PROGRESS_CREATE_SPREADSHEET);
if (spreadsheetId == null) {
if (!createSpreadSheet(title)) {
Log.d(TAG, "Unable to create a new spreadsheet");
return false;
}
// The previous creation might have succeeded even though GData
// reported an error. Seems to be a know bug.
// See http://code.google.com/p/gdata-issues/issues/detail?id=929
// Try to find the created spreadsheet.
if (spreadsheetId == null) {
if (!fetchSpreadSheetId(title, true)) {
Log.d(TAG, "Unable to check if the new spreadsheet is created");
return false;
}
if (spreadsheetId == null) {
Log.d(TAG, "Unable to create a new spreadsheet");
return false;
}
}
}
// Get the worksheet ID
publishProgress(PROGRESS_GET_WORKSHEET_ID);
if (!fetchWorksheetId()) {
return retryTask();
}
if (worksheetId == null) {
Log.d(TAG, "Unable to get a worksheet ID");
return false;
}
// Add the track info
publishProgress(PROGRESS_ADD_TRACK_INFO);
if (!addTrackInfo(track)) {
Log.d(TAG, "Unable to add track info");
return false;
}
publishProgress(PROGRESS_COMPLETE);
return true;
}
@Override
protected void invalidateToken() {
AccountManager.get(context).invalidateAuthToken(Constants.ACCOUNT_TYPE, documentsAuthToken);
AccountManager.get(context).invalidateAuthToken(Constants.ACCOUNT_TYPE, spreadsheetsAuthToken);
}
/**
* Fetches the spreadsheet id. Sets the instance variable
* {@link SendDocsAsyncTask#spreadsheetId}.
*
* @param title the spreadsheet title
* @param waitFirst wait before checking
* @return true if completes.
*/
private boolean fetchSpreadSheetId(String title, boolean waitFirst) {
if (isCancelled()) {
return false;
}
if (waitFirst) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Log.d(TAG, "Unable to wait", e);
return false;
}
}
try {
spreadsheetId = SendDocsUtils.getSpreadsheetId(title, documentsClient, documentsAuthToken);
} catch (ParseException e) {
Log.d(TAG, "Unable to fetch spreadsheet ID", e);
return false;
} catch (HttpException e) {
Log.d(TAG, "Unable to fetch spreadsheet ID", e);
return false;
} catch (IOException e) {
Log.d(TAG, "Unable to fetch spreadsheet ID", e);
return false;
}
if (spreadsheetId == null) {
// Waiting a few seconds and trying again. Maybe the server just had a
// hickup (unfortunately that happens quite a lot...).
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Log.d(TAG, "Unable to wait", e);
return false;
}
try {
spreadsheetId = SendDocsUtils.getSpreadsheetId(title, documentsClient, documentsAuthToken);
} catch (ParseException e) {
Log.d(TAG, "Unable to fetch spreadsheet ID", e);
return false;
} catch (HttpException e) {
Log.d(TAG, "Unable to fetch spreadsheet ID", e);
return false;
} catch (IOException e) {
Log.d(TAG, "Unable to fetch spreadsheet ID", e);
return false;
}
}
return true;
}
/**
* Creates a spreadsheet. If successful, sets the instance variable
* {@link SendDocsAsyncTask#spreadsheetId}.
*
* @param spreadsheetTitle the spreadsheet title
* @return true if completes.
*/
private boolean createSpreadSheet(String spreadsheetTitle) {
if (isCancelled()) {
return false;
}
try {
spreadsheetId = SendDocsUtils.createSpreadsheet(
spreadsheetTitle, documentsAuthToken, context);
} catch (IOException e) {
Log.d(TAG, "Unable to create spreadsheet", e);
return false;
}
return true;
}
/**
* Fetches the worksheet ID. Sets the instance variable
* {@link SendDocsAsyncTask#worksheetId}.
*
* @return true if completes.
*/
private boolean fetchWorksheetId() {
if (isCancelled()) {
return false;
}
try {
worksheetId = SendDocsUtils.getWorksheetId(
spreadsheetId, spreadsheetsClient, spreadsheetsAuthToken);
} catch (IOException e) {
Log.d(TAG, "Unable to fetch worksheet ID", e);
return false;
} catch (AuthenticationException e) {
Log.d(TAG, "Unable to fetch worksheet ID", e);
return false;
} catch (ParseException e) {
Log.d(TAG, "Unable to fetch worksheet ID", e);
return false;
}
return true;
}
/**
* Adds track info to a worksheet.
*
* @param track the track
* @return true if completes.
*/
private boolean addTrackInfo(Track track) {
if (isCancelled()) {
return false;
}
try {
SendDocsUtils.addTrackInfo(track, spreadsheetId, worksheetId, spreadsheetsAuthToken, context);
} catch (IOException e) {
Log.d(TAG, "Unable to add track info", e);
return false;
}
return true;
}
}
@@ -0,0 +1,421 @@
/*
* Copyright 2012 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.fusiontables.SendFusionTablesUtils;
import com.google.android.apps.mytracks.io.gdata.docs.DocumentsClient;
import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient;
import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient.WorksheetEntry;
import com.google.android.apps.mytracks.io.maps.SendMapsUtils;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.ResourceUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
import com.google.wireless.gdata.client.HttpException;
import com.google.wireless.gdata.data.Entry;
import com.google.wireless.gdata.parser.GDataParser;
import com.google.wireless.gdata.parser.ParseException;
import com.google.wireless.gdata2.client.AuthenticationException;
import android.content.Context;
import android.util.Log;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.util.Locale;
/**
* Utilities for sending a track to Google Docs.
*
* @author Sandor Dornbush
* @author Matthew Simmons
*/
public class SendDocsUtils {
@VisibleForTesting
public static final String GET_SPREADSHEET_BY_TITLE_URI =
"https://docs.google.com/feeds/documents/private/full?"
+ "category=mine,spreadsheet&title=%s&title-exact=true";
private static final String CREATE_SPREADSHEET_URI =
"https://docs.google.com/feeds/documents/private/full";
private static final String GET_WORKSHEETS_URI =
"https://spreadsheets.google.com/feeds/worksheets/%s/private/full";
@VisibleForTesting
public static final String GET_WORKSHEET_URI =
"https://spreadsheets.google.com/feeds/list/%s/%s/private/full";
@VisibleForTesting
public static final String SPREADSHEET_ID_PREFIX =
"https://docs.google.com/feeds/documents/private/full/spreadsheet%3A";
@VisibleForTesting
public static final String CONTENT_TYPE = "Content-Type";
@VisibleForTesting
public static final String ATOM_FEED_MIME_TYPE = "application/atom+xml";
private static final String OPENDOCUMENT_SPREADSHEET_MIME_TYPE =
"application/x-vnd.oasis.opendocument.spreadsheet";
@VisibleForTesting
public static final String AUTHORIZATION = "Authorization";
@VisibleForTesting
public static final String AUTHORIZATION_PREFIX = "GoogleLogin auth=";
private static final String SLUG = "Slug";
// Google Docs can only parse numbers in the English locale.
private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance(Locale.ENGLISH);
private static final NumberFormat INTEGER_FORMAT = NumberFormat.getIntegerInstance(
Locale.ENGLISH);
static {
NUMBER_FORMAT.setMaximumFractionDigits(2);
NUMBER_FORMAT.setMinimumFractionDigits(2);
}
private static final String TAG = SendDocsUtils.class.getSimpleName();
private SendDocsUtils() {}
/**
* Gets the spreadsheet id of a spreadsheet. Returns null if the spreadsheet
* doesn't exist.
*
* @param title the title of the spreadsheet
* @param documentsClient the documents client
* @param authToken the auth token
* @return spreadsheet id or null if it doesn't exist.
*/
public static String getSpreadsheetId(
String title, DocumentsClient documentsClient, String authToken)
throws IOException, ParseException, HttpException {
GDataParser gDataParser = null;
try {
String uri = String.format(Locale.US, GET_SPREADSHEET_BY_TITLE_URI, URLEncoder.encode(title));
gDataParser = documentsClient.getParserForFeed(Entry.class, uri, authToken);
gDataParser.init();
while (gDataParser.hasMoreData()) {
Entry entry = gDataParser.readNextEntry(null);
String entryTitle = entry.getTitle();
if (entryTitle.equals(title)) {
return getEntryId(entry);
}
}
return null;
} finally {
if (gDataParser != null) {
gDataParser.close();
}
}
}
/**
* Gets the id from an entry. Returns null if not available.
*
* @param entry the entry
*/
@VisibleForTesting
static String getEntryId(Entry entry) {
String entryId = entry.getId();
if (entryId.startsWith(SPREADSHEET_ID_PREFIX)) {
return entryId.substring(SPREADSHEET_ID_PREFIX.length());
}
return null;
}
/**
* Creates a new spreadsheet with the given title. Returns the spreadsheet ID
* if successful. Returns null otherwise. Note that it is possible that a new
* spreadsheet is created, but the returned ID is null.
*
* @param title the title
* @param authToken the auth token
* @param context the context
*/
public static String createSpreadsheet(String title, String authToken, Context context)
throws IOException {
URL url = new URL(CREATE_SPREADSHEET_URI);
URLConnection conn = url.openConnection();
conn.addRequestProperty(CONTENT_TYPE, OPENDOCUMENT_SPREADSHEET_MIME_TYPE);
conn.addRequestProperty(SLUG, title);
conn.addRequestProperty(AUTHORIZATION, AUTHORIZATION_PREFIX + authToken);
conn.setDoOutput(true);
OutputStream outputStream = conn.getOutputStream();
ResourceUtils.readBinaryFileToOutputStream(
context, R.raw.mytracks_empty_spreadsheet, outputStream);
// Get the response
BufferedReader bufferedReader = null;
StringBuilder resultBuilder = new StringBuilder();
try {
bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
resultBuilder.append(line);
}
} catch (FileNotFoundException e) {
// The GData API sometimes throws an error, even though creation of
// the document succeeded. In that case let's just return. The caller
// then needs to check if the doc actually exists.
Log.d(TAG, "Unable to read result after creating a spreadsheet", e);
return null;
} finally {
outputStream.close();
if (bufferedReader != null) {
bufferedReader.close();
}
}
return getNewSpreadsheetId(resultBuilder.toString());
}
/**
* Gets the spreadsheet id from a create spreadsheet result.
*
* @param result the create spreadsheet result
*/
@VisibleForTesting
static String getNewSpreadsheetId(String result) {
int idTagIndex = result.indexOf("<id>");
if (idTagIndex == -1) {
return null;
}
int idTagCloseIndex = result.indexOf("</id>", idTagIndex);
if (idTagCloseIndex == -1) {
return null;
}
int idStringStart = result.indexOf(SPREADSHEET_ID_PREFIX, idTagIndex);
if (idStringStart == -1) {
return null;
}
return result.substring(idStringStart + SPREADSHEET_ID_PREFIX.length(), idTagCloseIndex);
}
/**
* Gets the first worksheet ID of a spreadsheet. Returns null if not
* available.
*
* @param spreadsheetId the spreadsheet ID
* @param spreadsheetClient the spreadsheet client
* @param authToken the auth token
*/
public static String getWorksheetId(
String spreadsheetId, SpreadsheetsClient spreadsheetClient, String authToken)
throws IOException, AuthenticationException, ParseException {
GDataParser gDataParser = null;
try {
String uri = String.format(Locale.US, GET_WORKSHEETS_URI, spreadsheetId);
gDataParser = spreadsheetClient.getParserForWorksheetsFeed(uri, authToken);
gDataParser.init();
if (!gDataParser.hasMoreData()) {
Log.d(TAG, "No worksheet");
return null;
}
// Get the first worksheet
WorksheetEntry worksheetEntry =
(WorksheetEntry) gDataParser.readNextEntry(new WorksheetEntry());
return getWorksheetEntryId(worksheetEntry);
} finally {
if (gDataParser != null) {
gDataParser.close();
}
}
}
/**
* Gets the worksheet id from a worksheet entry. Returns null if not available.
*
* @param entry the worksheet entry
*/
@VisibleForTesting
static String getWorksheetEntryId(WorksheetEntry entry) {
String id = entry.getId();
int lastSlash = id.lastIndexOf('/');
if (lastSlash == -1) {
Log.d(TAG, "No id");
return null;
}
return id.substring(lastSlash + 1);
}
/**
* Adds a track's info as a row in a worksheet.
*
* @param track the track
* @param spreadsheetId the spreadsheet ID
* @param worksheetId the worksheet ID
* @param authToken the auth token
* @param context the context
*/
public static void addTrackInfo(
Track track, String spreadsheetId, String worksheetId, String authToken, Context context)
throws IOException {
String worksheetUri = String.format(Locale.US, GET_WORKSHEET_URI, spreadsheetId, worksheetId);
boolean metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
addRow(worksheetUri, getRowContent(track, metricUnits, context), authToken);
}
/**
* Gets the row content containing the track's info.
*
* @param track the track
* @param metricUnits true to use metric
* @param context the context
*/
@VisibleForTesting
static String getRowContent(Track track, boolean metricUnits, Context context) {
TripStatistics stats = track.getTripStatistics();
String distanceUnit = context.getString(
metricUnits ? R.string.unit_kilometer : R.string.unit_mile);
String speedUnit = context.getString(
metricUnits ? R.string.unit_kilometer_per_hour : R.string.unit_mile_per_hour);
String elevationUnit = context.getString(
metricUnits ? R.string.unit_meter : R.string.unit_feet);
StringBuilder builder = new StringBuilder().append("<entry xmlns='http://www.w3.org/2005/Atom' "
+ "xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'>");
appendTag(builder, "name", track.getName());
appendTag(builder, "description", track.getDescription());
appendTag(builder, "date", StringUtils.formatDateTime(context, stats.getStartTime()));
appendTag(builder, "totaltime", StringUtils.formatElapsedTimeWithHour(stats.getTotalTime()));
appendTag(builder, "movingtime", StringUtils.formatElapsedTimeWithHour(stats.getMovingTime()));
appendTag(builder, "distance", getDistance(stats.getTotalDistance(), metricUnits));
appendTag(builder, "distanceunit", distanceUnit);
appendTag(builder, "averagespeed", getSpeed(stats.getAverageSpeed(), metricUnits));
appendTag(builder, "averagemovingspeed", getSpeed(stats.getAverageMovingSpeed(), metricUnits));
appendTag(builder, "maxspeed", getSpeed(stats.getMaxSpeed(), metricUnits));
appendTag(builder, "speedunit", speedUnit);
appendTag(builder, "elevationgain", getElevation(stats.getTotalElevationGain(), metricUnits));
appendTag(builder, "minelevation", getElevation(stats.getMinElevation(), metricUnits));
appendTag(builder, "maxelevation", getElevation(stats.getMaxElevation(), metricUnits));
appendTag(builder, "elevationunit", elevationUnit);
String map = SendMapsUtils.getMapUrl(track);
if (map == null) {
map = context.getString(R.string.value_unknown);
}
appendTag(builder, "map", map);
String fusionTable = SendFusionTablesUtils.getMapUrl(track);
if (fusionTable == null) {
fusionTable = context.getString(R.string.value_unknown);
}
appendTag(builder, "fusiontable", fusionTable);
builder.append("</entry>");
return builder.toString();
}
/**
* Appends a name-value pair as a gsx tag to a string builder.
*
* @param stringBuilder the string builder
* @param name the name
* @param value the value
*/
@VisibleForTesting
static void appendTag(StringBuilder stringBuilder, String name, String value) {
stringBuilder
.append("<gsx:")
.append(name)
.append(">")
.append(StringUtils.formatCData(value))
.append("</gsx:")
.append(name)
.append(">");
}
/**
* Gets the distance. Performs unit conversion and formatting.
*
* @param distanceInMeter the distance in meters
* @param metricUnits true to use metric
*/
@VisibleForTesting
static final String getDistance(double distanceInMeter, boolean metricUnits) {
double distanceInKilometer = distanceInMeter * UnitConversions.M_TO_KM;
double distance = metricUnits ? distanceInKilometer
: distanceInKilometer * UnitConversions.KM_TO_MI;
return NUMBER_FORMAT.format(distance);
}
/**
* Gets the speed. Performs unit conversion and formatting.
*
* @param speedInMeterPerSecond the speed in meters per second
* @param metricUnits true to use metric
*/
@VisibleForTesting
static final String getSpeed(double speedInMeterPerSecond, boolean metricUnits) {
double speedInKilometerPerHour = speedInMeterPerSecond * UnitConversions.MS_TO_KMH;
double speed = metricUnits ? speedInKilometerPerHour
: speedInKilometerPerHour * UnitConversions.KM_TO_MI;
return NUMBER_FORMAT.format(speed);
}
/**
* Gets the elevation. Performs unit conversion and formatting.
*
* @param elevationInMeter the elevation value in meters
* @param metricUnits true to use metric
*/
@VisibleForTesting
static final String getElevation(double elevationInMeter, boolean metricUnits) {
double elevation = metricUnits ? elevationInMeter : elevationInMeter * UnitConversions.M_TO_FT;
return INTEGER_FORMAT.format(elevation);
}
/**
* Adds a row to a Google Spreadsheet worksheet.
*
* @param worksheetUri the worksheet URI
* @param rowContent the row content
* @param authToken the auth token
*/
private static final void addRow(String worksheetUri, String rowContent, String authToken)
throws IOException {
URL url = new URL(worksheetUri);
URLConnection conn = url.openConnection();
conn.addRequestProperty(CONTENT_TYPE, ATOM_FEED_MIME_TYPE);
conn.addRequestProperty(AUTHORIZATION, AUTHORIZATION_PREFIX + authToken);
conn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
writer.write(rowContent);
writer.flush();
// Get the response
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((reader.readLine()) != null) {
// Just read till the end
}
writer.close();
reader.close();
}
}