diff --git a/MyTracks/libs/README.txt b/MyTracks/libs/README.txt
index b303dcf14..35a849f96 100644
--- a/MyTracks/libs/README.txt
+++ b/MyTracks/libs/README.txt
@@ -7,7 +7,7 @@ Android Support Package:
android-support-v4.jar (version 13)
Ant+:
-antlib.jar - see http://www.thisisant.com/pages/developer-zone/android-api
+antlib.jar - from Android_ANT_SDK_20120625.zip
Google APIs Client Library for Java:
google-api-client-1.12.0-beta.jar
diff --git a/MyTracks/libs/antlib.jar b/MyTracks/libs/antlib.jar
index b4ff8fe04..21d141ba9 100644
Binary files a/MyTracks/libs/antlib.jar and b/MyTracks/libs/antlib.jar differ
diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml
index 61c35da82..90f50c968 100644
--- a/MyTracks/res/values/strings.xml
+++ b/MyTracks/res/values/strings.xml
@@ -384,9 +384,9 @@ limitations under the License.
- Average moving pace: %1$.2f min/km (%2$.1f min/mi)
+ %1$s pace in minutes per kilometer
+ %2$s pace in minutes per mile">
+ Average moving pace: %1$s min/km (%2$s min/mi)
- Average pace: %1$.2f min/km (%2$.1f min/mi)
+ %1$s pace in minutes per kilometer
+ %2$s pace in minutes per mile">
+ Average pace: %1$s min/km (%2$s min/mi)
- Fastest pace: %1$.2f min/km (%2$.1f min/mi)
+ %1$s pace in minutes per kilometer
+ %2$s pace in minutes per mile">
+ Fastest pace: %1$s min/km (%2$s min/mi)
@@ -497,12 +497,12 @@ limitations under the License.
Moving time: %1$s
- Pace (hr/mi)
+ translation_description="Pace in imperial units, minutes per mile.">
+ Pace (min/mi)
- Pace (hr/km)
+ translation_description="Pace in metric units, minutes per kilometer.">
+ Pace (min/km)
Preferred rate
@@ -2131,7 +2131,7 @@ limitations under the License.
Moving time
Pace
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ChartView.java b/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
index 86b12877d..a3db6dae2 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
@@ -653,13 +653,14 @@ public class ChartView extends View {
canvas.drawLine(x, y, x + effectiveWidth, y, axisPaint);
String label = getXAxisLabel();
Rect rect = getRect(axisPaint, label);
- canvas.drawText(label, x + effectiveWidth + spacer, y + ((int) rect.height() / 2), axisPaint);
-
+ int yOffset = (int) rect.height() / 2;
+ canvas.drawText(label, x + effectiveWidth + spacer, y + yOffset, axisPaint);
+
double interval = getXAxisInterval();
ArrayList markerPositions = getXAxisMarkerPositions(interval);
NumberFormat numberFormat = interval < 1 ? X_FRACTION_FORMAT : X_NUMBER_FORMAT;
for (int i = 0; i < markerPositions.size(); i++) {
- drawXAxisMarker(canvas, markerPositions.get(i), numberFormat);
+ drawXAxisMarker(canvas, markerPositions.get(i), numberFormat, spacer + yOffset);
}
}
@@ -682,12 +683,14 @@ public class ChartView extends View {
* @param canvas
* @param value value
* @param numberFormat the number format
+ * @param spacing the spacing between x axis and marker
*/
- private void drawXAxisMarker(Canvas canvas, double value, NumberFormat numberFormat) {
+ private void drawXAxisMarker(
+ Canvas canvas, double value, NumberFormat numberFormat, int spacing) {
String marker = chartByDistance ? numberFormat.format(value)
: StringUtils.formatElapsedTime((long) value);
Rect rect = getRect(xAxisMarkerPaint, marker);
- canvas.drawText(marker, getX(value), topBorder + effectiveHeight + spacer + rect.height(),
+ canvas.drawText(marker, getX(value), topBorder + effectiveHeight + spacing + rect.height(),
xAxisMarkerPaint);
}
@@ -906,8 +909,11 @@ public class ChartView extends View {
leftBorder = (int) (density * BORDER + markerLength);
int[] titleDimensions = getTitleDimenions();
topBorder = (int) (density * BORDER + titleDimensions[0] * (titleDimensions[1] + spacer));
- bottomBorder = (int) (density * BORDER + getRect(xAxisMarkerPaint, "1").height() + spacer);
- rightBorder = (int) (density * BORDER + getRect(axisPaint, getXAxisLabel()).width() + spacer);
+ Rect xAxisLabelRect = getRect(axisPaint, getXAxisLabel());
+ // border + x axis marker + spacer + .5 x axis label
+ bottomBorder = (int) (density * BORDER + getRect(xAxisMarkerPaint, "1").height() + spacer
+ + (int) (xAxisLabelRect.height() / 2));
+ rightBorder = (int) (density * BORDER + xAxisLabelRect.width() + spacer);
updateEffectiveDimensions();
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java b/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java
index 5edb7c59d..0c5848c07 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java
@@ -27,14 +27,12 @@ import com.google.android.maps.mytracks.R;
import com.google.protobuf.InvalidProtocolBufferException;
import android.os.Bundle;
+import android.os.Handler;
import android.os.RemoteException;
import android.text.format.DateFormat;
import android.util.Log;
import android.widget.TextView;
-import java.util.Timer;
-import java.util.TimerTask;
-
/**
* An activity that displays information about sensors.
*
@@ -43,12 +41,14 @@ import java.util.TimerTask;
public class SensorStateActivity extends AbstractMyTracksActivity {
private static final String TAG = SensorStateActivity.class.getName();
- private static final long REFRESH_PERIOD_MS = 250;
+ private static final long ONE_SECOND = 1000;
- /**
- * A Runnable to update the UI.
- */
- private final Runnable updateRunnable = new Runnable() {
+ private TrackRecordingServiceConnection trackRecordingServiceConnection;
+ private Handler handler;
+ private SensorManager tempSensorManager;
+
+ private final Runnable updateUiRunnable = new Runnable() {
+ @Override
public void run() {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
.getServiceIfBound();
@@ -69,30 +69,15 @@ public class SensorStateActivity extends AbstractMyTracksActivity {
stopTempSensorManager();
updateFromSystemSensorManager();
}
+ handler.postDelayed(this, ONE_SECOND);
}
};
- /**
- * A TimeTask to update the UI.
- */
- private class UpdateTimerTask extends TimerTask {
- @Override
- public void run() {
- if (isVisible) {
- runOnUiThread(updateRunnable);
- }
- }
- };
-
- private TrackRecordingServiceConnection trackRecordingServiceConnection;
- private boolean isVisible = false;
- private Timer timer = null;
- private SensorManager tempSensorManager = null;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, null);
+ handler = new Handler();
}
@Override
@@ -104,18 +89,13 @@ public class SensorStateActivity extends AbstractMyTracksActivity {
@Override
protected void onResume() {
super.onResume();
- isVisible = true;
- timer = new Timer();
- timer.schedule(new UpdateTimerTask(), 0, REFRESH_PERIOD_MS);
+ handler.post(updateUiRunnable);
}
@Override
protected void onPause() {
super.onPause();
- isVisible = false;
- timer.cancel();
- timer.purge();
- timer = null;
+ handler.removeCallbacks(updateUiRunnable);
stopTempSensorManager();
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java b/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java
index e1b16c239..18fdb13cf 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java
@@ -367,7 +367,8 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
@Override
public Loader onCreateLoader(int arg0, Bundle arg1) {
return new CursorLoader(TrackListActivity.this, TracksColumns.CONTENT_URI, PROJECTION, null,
- null, TracksColumns.SHAREDWITHME + " ASC, " + TracksColumns.STARTTIME + " DESC");
+ null, "IFNULL(" + TracksColumns.SHAREDWITHME + ",0) ASC, " + TracksColumns.STARTTIME
+ + " DESC");
}
@Override
diff --git a/MyTracks/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImpl.java b/MyTracks/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImpl.java
index e647dc4f2..42cbeae64 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImpl.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImpl.java
@@ -24,7 +24,6 @@ import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
-import android.util.Pair;
import java.util.Vector;
@@ -117,25 +116,24 @@ public class DescriptionGeneratorImpl implements DescriptionGenerator {
writeTime(stats.getMovingTime(), builder, R.string.description_moving_time, lineBreak);
// Average speed
- Pair averageSpeed = writeSpeed(
- stats.getAverageSpeed(), builder, R.string.description_average_speed, lineBreak);
+ writeSpeed(stats.getAverageSpeed(), builder, R.string.description_average_speed, lineBreak);
// Average moving speed
- Pair averageMovingSpeed = writeSpeed(stats.getAverageMovingSpeed(), builder,
- R.string.description_average_moving_speed, lineBreak);
+ writeSpeed(stats.getAverageMovingSpeed(), builder, R.string.description_average_moving_speed,
+ lineBreak);
// Max speed
- Pair maxSpeed = writeSpeed(
- stats.getMaxSpeed(), builder, R.string.description_max_speed, lineBreak);
+ writeSpeed(stats.getMaxSpeed(), builder, R.string.description_max_speed, lineBreak);
// Average pace
- writePace(averageSpeed, builder, R.string.description_average_pace, lineBreak);
+ writePace(stats.getAverageSpeed(), builder, R.string.description_average_pace, lineBreak);
// Average moving pace
- writePace(averageMovingSpeed, builder, R.string.description_average_moving_pace, lineBreak);
+ writePace(stats.getAverageMovingSpeed(), builder, R.string.description_average_moving_pace,
+ lineBreak);
// Fastest pace
- writePace(maxSpeed, builder, R.string.description_fastest_pace, lineBreak);
+ writePace(stats.getMaxSpeed(), builder, R.string.description_fastest_pace, lineBreak);
// Max elevation
writeElevation(stats.getMaxElevation(), builder, R.string.description_max_elevation, lineBreak);
@@ -199,34 +197,38 @@ public class DescriptionGeneratorImpl implements DescriptionGenerator {
* @param builder StringBuilder to append speed
* @param resId resource id of speed string
* @param lineBreak line break string
- * @return a pair of speed, first in kilometers per hour, second in miles per
- * hour.
*/
@VisibleForTesting
- Pair writeSpeed(
+ void writeSpeed(
double speed, StringBuilder builder, int resId, String lineBreak) {
double speedInKmHr = speed * UnitConversions.MS_TO_KMH;
double speedInMiHr = speedInKmHr * UnitConversions.KM_TO_MI;
builder.append(context.getString(resId, speedInKmHr, speedInMiHr));
builder.append(lineBreak);
- return Pair.create(speedInKmHr, speedInMiHr);
}
/**
* Writes pace.
- *
- * @param speed a pair of speed, first in kilometers per hour, second in miles
- * per hour
+ *
+ * @param speed speed in meters per second
* @param builder StringBuilder to append pace
* @param resId resource id of pace string
* @param lineBreak line break string
*/
@VisibleForTesting
- void writePace(
- Pair speed, StringBuilder builder, int resId, String lineBreak) {
- double paceInMinKm = getPace(speed.first);
- double paceInMinMi = getPace(speed.second);
- builder.append(context.getString(resId, paceInMinKm, paceInMinMi));
+ void writePace(double speed, StringBuilder builder, int resId, String lineBreak) {
+ String[] paceInMetrics = StringUtils.getSpeedParts(context, speed, true, false);
+ String[] paceInImperial = StringUtils.getSpeedParts(context, speed, false, false);
+
+ if (paceInMetrics[0] == null) {
+ paceInMetrics[0] = context.getString(R.string.value_unknown);
+ }
+
+ if (paceInImperial[0] == null) {
+ paceInImperial[0] = context.getString(R.string.value_unknown);
+ }
+
+ builder.append(context.getString(resId, paceInMetrics[0], paceInImperial[0]));
builder.append(lineBreak);
}
@@ -262,14 +264,4 @@ public class DescriptionGeneratorImpl implements DescriptionGenerator {
builder.append(context.getString(resId, gradeInPercent));
builder.append(lineBreak);
}
-
- /**
- * Gets pace (in minutes) from speed.
- *
- * @param speed speed in hours
- */
- @VisibleForTesting
- double getPace(double speed) {
- return speed == 0 ? 0.0 : 60.0 / speed; // convert from hours to minutes
- }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java b/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java
index 8ba075d6a..d596e4221 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java
@@ -134,9 +134,10 @@ public class TrackDataHub implements DataSourceListener {
started = false;
dataSourceManager.unregisterAllListeners();
- handlerThread.getLooper().quit();
-
- handlerThread = null;
+ if (handlerThread != null) {
+ handlerThread.getLooper().quit();
+ handlerThread = null;
+ }
handler = null;
dataSource = null;
dataSourceManager = null;
diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/EulaDialogFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/EulaDialogFragment.java
index 02e9316e8..737dcc4e5 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/fragments/EulaDialogFragment.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/EulaDialogFragment.java
@@ -27,7 +27,11 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
+import android.text.SpannableString;
+import android.text.method.LinkMovementMethod;
+import android.text.util.Linkify;
import android.view.KeyEvent;
+import android.widget.TextView;
import java.util.Locale;
@@ -89,8 +93,12 @@ public class EulaDialogFragment extends DialogFragment {
fragmentActivity = getActivity();
boolean hasAccepted = getArguments().getBoolean(KEY_HAS_ACCEPTED);
- AlertDialog.Builder builder = new AlertDialog.Builder(fragmentActivity).setMessage(
- getEulaText()).setTitle(R.string.eula_title);
+
+ SpannableString message = new SpannableString(getEulaText());
+ Linkify.addLinks(message, Linkify.WEB_URLS);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(fragmentActivity).setMessage(message)
+ .setTitle(R.string.eula_title);
if (hasAccepted) {
builder.setPositiveButton(R.string.generic_ok, null);
@@ -117,10 +125,17 @@ public class EulaDialogFragment extends DialogFragment {
caller.onEulaDone();
}
});
- }
+ }
return builder.create();
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ TextView textView = (TextView) getDialog().findViewById(android.R.id.message);
+ textView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
@Override
public void onCancel(DialogInterface arg0) {
caller.onEulaDone();
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesAsyncTask.java
index bf35f2a40..e49ace669 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesAsyncTask.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesAsyncTask.java
@@ -237,7 +237,8 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
int count = cursor.getCount();
List locations = new ArrayList(MAX_POINTS_PER_UPLOAD);
- Location lastLocation = null;
+ Location lastValidLocation = null;
+ boolean sentStartMarker = false;
for (int i = 0; i < count; i++) {
cursor.moveToPosition(i);
@@ -245,14 +246,15 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
Location location = myTracksProviderUtils.createTrackPoint(cursor);
locations.add(location);
- if (i == 0) {
- // Create a start marker
- String name = context.getString(R.string.marker_label_start, track.getName());
- createNewPoint(fusiontables, tableId, name, "", location, MARKER_TYPE_START);
+ if (LocationUtils.isValidLocation(location)) {
+ lastValidLocation = location;
}
- if (LocationUtils.isValidLocation(location)) {
- lastLocation = location;
+ if (!sentStartMarker && lastValidLocation != null) {
+ // Create a start marker
+ String name = context.getString(R.string.marker_label_start, track.getName());
+ createNewPoint(fusiontables, tableId, name, "", lastValidLocation, MARKER_TYPE_START);
+ sentStartMarker = true;
}
// Upload periodically
@@ -274,11 +276,12 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
}
// Create an end marker
- if (lastLocation != null) {
+ if (lastValidLocation != null) {
String name = context.getString(R.string.marker_label_end, track.getName());
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
String description = descriptionGenerator.generateTrackDescription(track, null, null, true);
- createNewPoint(fusiontables, tableId, name, description, lastLocation, MARKER_TYPE_END);
+ createNewPoint(
+ fusiontables, tableId, name, description, lastValidLocation, MARKER_TYPE_END);
}
return true;
} finally {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTask.java
index 11a5fb040..f0d8503c9 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTask.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTask.java
@@ -244,7 +244,8 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
int count = cursor.getCount();
List locations = new ArrayList(MAX_POINTS_PER_UPLOAD);
- Location lastLocation = null;
+ Location lastValidLocation = null;
+ boolean sentStartMarker = false;
// For chart server, limit the number of elevation readings to 250.
int elevationSamplingFrequency = Math.max(1, (int) (count / 250.0));
@@ -261,13 +262,18 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
Location location = myTracksProviderUtils.createTrackPoint(cursor);
locations.add(location);
- if (i == 0) {
+ if (LocationUtils.isValidLocation(location)) {
+ lastValidLocation = location;
+ }
+
+ if (!sentStartMarker && lastValidLocation != null) {
// Create a start marker
if (!uploadMarker(context.getString(R.string.marker_label_start, track.getName()), "",
- START_ICON_URL, location)) {
+ START_ICON_URL, lastValidLocation)) {
Log.d(TAG, "Unable to create a start marker");
return false;
}
+ sentStartMarker = true;
}
tripStatisticsUpdater.addLocation(location, minRecordingDistance);
@@ -275,9 +281,6 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
}
- if (LocationUtils.isValidLocation(location)) {
- lastLocation = location;
- }
// Upload periodically
int readCount = i + 1;
@@ -298,14 +301,14 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
}
// Create an end marker
- if (lastLocation != null) {
+ if (lastValidLocation != null) {
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
track.setDescription(
descriptionGenerator.generateTrackDescription(track, distances, elevations, true));
if (!uploadMarker(context.getString(R.string.marker_label_end, track.getName()),
- track.getDescription(), END_ICON_URL, lastLocation)) {
+ track.getDescription(), END_ICON_URL, lastValidLocation)) {
Log.d(TAG, "Unable to create an end marker");
return false;
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
index 78bff4bbc..6e49b2564 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
@@ -133,8 +133,9 @@ public class TrackRecordingService extends Service {
private Location lastLocation;
private boolean currentSegmentHasLocation;
- // Timer to periodically invoke checkLocationListener
- private final Timer timer = new Timer();
+ // TimerTask to register location listener
+ private TimerTask timerTask;
+ private Timer timer;
// Handler for the timer to post a runnable to the main thread
private final Handler handler = new Handler();
@@ -247,15 +248,6 @@ public class TrackRecordingService extends Service {
}
};
- private TimerTask checkLocationListener = new TimerTask() {
- @Override
- public void run() {
- if (isRecording() && !isPaused()) {
- registerLocationListener();
- }
- }
- };
-
private final ConnectionCallbacks activityRecognitionCallbacks = new ConnectionCallbacks() {
@Override
public void onDisconnected() {}
@@ -301,10 +293,19 @@ public class TrackRecordingService extends Service {
// onSharedPreferenceChanged might not set recordingTrackId.
recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
- // Require announcementExecutor and splitExecutor to be created.
+ // Require voiceExecutor and splitExecutor to be created.
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
- timer.schedule(checkLocationListener, 0, ONE_MINUTE);
+ timerTask = new TimerTask() {
+ @Override
+ public void run() {
+ if (isRecording() && !isPaused()) {
+ registerLocationListener();
+ }
+ }
+ };
+ timer = new Timer("TrackRecordingServiceTimer");
+ timer.schedule(timerTask, 0, ONE_MINUTE);
/*
* Try to restart the previous recording track in case the service has been
@@ -357,10 +358,15 @@ public class TrackRecordingService extends Service {
showNotification(false);
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
- checkLocationListener.cancel();
- checkLocationListener = null;
- timer.cancel();
- timer.purge();
+ if (timerTask != null) {
+ timerTask.cancel();
+ timerTask = null;
+ }
+ if (timer != null) {
+ timer.cancel();
+ timer.purge();
+ timer = null;
+ }
unregisterLocationListener();
try {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/SensorManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/SensorManager.java
index 8b3787abf..36bcacde3 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/SensorManager.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/SensorManager.java
@@ -39,30 +39,8 @@ public abstract class SensorManager {
private SensorState sensorState = SensorState.NONE;
private long sensorStateTimestamp = System.currentTimeMillis();
- /**
- * A time task to check sensor connection.
- */
- private TimerTask checkSensorConnectionTimeTask = new TimerTask() {
- @Override
- public void run() {
- switch (getSensorState()) {
- case CONNECTING:
- if (System.currentTimeMillis() - sensorStateTimestamp > MAX_SENSOR_STATE_AGE) {
- Log.i(TAG, "Retry setUpChannel");
- setUpChannel();
- }
- break;
- case NONE:
- case DISCONNECTED:
- setUpChannel();
- break;
- default:
- break;
- }
- }
- };
-
- private final Timer timer = new Timer();
+ private TimerTask timerTask;
+ private Timer timer;
/**
* Returns true if the sensor is enabled.
@@ -89,14 +67,43 @@ public abstract class SensorManager {
*/
public void startSensor() {
setUpChannel();
- timer.schedule(checkSensorConnectionTimeTask, RETRY_PERIOD, RETRY_PERIOD);
+ timerTask = new TimerTask() {
+ @Override
+ public void run() {
+ switch (getSensorState()) {
+ case CONNECTING:
+ if (System.currentTimeMillis() - sensorStateTimestamp > MAX_SENSOR_STATE_AGE) {
+ Log.i(TAG, "Retry setUpChannel");
+ setUpChannel();
+ }
+ break;
+ case NONE:
+ case DISCONNECTED:
+ setUpChannel();
+ break;
+ default:
+ // CONNECTED or SENDING
+ break;
+ }
+ }
+ };
+ timer = new Timer("SensorManagerTimer");
+ timer.schedule(timerTask, RETRY_PERIOD, RETRY_PERIOD);
}
/**
* Stops the sensor.
*/
public void stopSensor() {
- timer.cancel();
+ if (timerTask != null) {
+ timerTask.cancel();
+ timerTask = null;
+ }
+ if (timer != null) {
+ timer.cancel();
+ timer.purge();
+ timer = null;
+ }
tearDownChannel();
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/TimerTaskExecutor.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/TimerTaskExecutor.java
index 50bcd85af..90021a233 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/TimerTaskExecutor.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/TimerTaskExecutor.java
@@ -33,10 +33,7 @@ public class TimerTaskExecutor {
private final PeriodicTask periodicTask;
private final TrackRecordingService trackRecordingService;
- /**
- * A timer to schedule the announcements. This is non-null if the task is in
- * started (scheduled) state.
- */
+ private TimerTask timerTask;
private Timer timer;
public TimerTaskExecutor(PeriodicTask periodicTask, TrackRecordingService trackRecordingService) {
@@ -50,6 +47,10 @@ public class TimerTaskExecutor {
* @param interval the interval in milliseconds
*/
public void scheduleTask(long interval) {
+ if (interval <= 0) {
+ return;
+ }
+
if (!trackRecordingService.isRecording() || trackRecordingService.isPaused()) {
return;
}
@@ -59,43 +60,32 @@ public class TimerTaskExecutor {
return;
}
- if (timer != null) {
- timer.cancel();
- timer.purge();
- } else {
- // First start, or we were previously shut down.
- periodicTask.start();
- }
-
- timer = new Timer();
- if (interval <= 0) {
- return;
- }
-
+ shutdown();
+ periodicTask.start();
+ timerTask = new TimerTask() {
+ @Override
+ public void run() {
+ periodicTask.run(trackRecordingService);
+ }
+ };
+ timer = new Timer("TimerTaskExecutorTimer");
long next = System.currentTimeMillis() + interval - (tripStatistics.getTotalTime() % interval);
- timer.scheduleAtFixedRate(new PeriodicTimerTask(), new Date(next), interval);
+ timer.scheduleAtFixedRate(timerTask, new Date(next), interval);
}
/**
* Shuts down.
*/
public void shutdown() {
+ if (timerTask != null) {
+ timerTask.cancel();
+ timerTask = null;
+ }
if (timer != null) {
timer.cancel();
timer.purge();
timer = null;
- periodicTask.shutdown();
- }
- }
-
- /**
- * The timer task to announce the trip status.
- */
- private class PeriodicTimerTask extends TimerTask {
-
- @Override
- public void run() {
- periodicTask.run(trackRecordingService);
}
+ periodicTask.shutdown();
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/StringUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/StringUtils.java
index 0e09a817e..9771fbbf0 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/StringUtils.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/StringUtils.java
@@ -213,19 +213,18 @@ public class StringUtils {
return result;
}
speed *= UnitConversions.MS_TO_KMH;
- if (metricUnits) {
- if (!reportSpeed) {
- // convert from hours to minutes
- speed = speed == 0 ? 0.0 : 60.0 / speed;
- }
- } else {
+ if (!metricUnits) {
speed *= UnitConversions.KM_TO_MI;
- if (!reportSpeed) {
- // convert from hours to minutes
- speed = speed == 0 ? 0.0 : 60.0 / speed;
- }
}
- result[0] = String.format("%.2f", speed);
+ if (reportSpeed) {
+ result[0] = String.format("%.2f", speed);
+ } else {
+ // convert from hours to minutes
+ double pace = speed == 0 ? 0.0 : 60.0 / speed;
+ int minutes = (int) pace;
+ int seconds = (int) Math.round((pace - minutes) * 60.0);
+ result[0] = String.format("%d:%02d", minutes, seconds);
+ }
return result;
}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImplTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImplTest.java
index 245e5f3bd..d2d672693 100644
--- a/MyTracksTest/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImplTest.java
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImplTest.java
@@ -68,9 +68,9 @@ public class DescriptionGeneratorImplTest extends AndroidTestCase {
+ "Average speed: 120.00 km/h (74.6 mi/h)
"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)
"
+ "Max speed: 360.00 km/h (223.7 mi/h)
"
- + "Average pace: 0.50 min/km (0.8 min/mi)
"
- + "Average moving pace: 0.25 min/km (0.4 min/mi)
"
- + "Fastest pace: 0.17 min/km (0.3 min/mi)
"
+ + "Average pace: 0:30 min/km (0:48 min/mi)
"
+ + "Average moving pace: 0:15 min/km (0:24 min/mi)
"
+ + "Fastest pace: 0:10 min/km (0:16 min/mi)
"
+ "Max elevation: 550 m (1804 ft)
"
+ "Min elevation: -500 m (-1640 ft)
"
+ "Elevation gain: 6000 m (19685 ft)
"
@@ -103,9 +103,9 @@ public class DescriptionGeneratorImplTest extends AndroidTestCase {
+ "Average speed: 120.00 km/h (74.6 mi/h)\n"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)\n"
+ "Max speed: 360.00 km/h (223.7 mi/h)\n"
- + "Average pace: 0.50 min/km (0.8 min/mi)\n"
- + "Average moving pace: 0.25 min/km (0.4 min/mi)\n"
- + "Fastest pace: 0.17 min/km (0.3 min/mi)\n"
+ + "Average pace: 0:30 min/km (0:48 min/mi)\n"
+ + "Average moving pace: 0:15 min/km (0:24 min/mi)\n"
+ + "Fastest pace: 0:10 min/km (0:16 min/mi)\n"
+ "Max elevation: 550 m (1804 ft)\n"
+ "Min elevation: -500 m (-1640 ft)\n"
+ "Elevation gain: 6000 m (19685 ft)\n"
@@ -162,9 +162,8 @@ public class DescriptionGeneratorImplTest extends AndroidTestCase {
*/
public void testWritePace() {
StringBuilder builder = new StringBuilder();
- descriptionGenerator.writePace(
- new Pair(1.1, 2.2), builder, R.string.description_average_pace, "\n");
- assertEquals("Average pace: 54.55 min/km (27.3 min/mi)\n", builder.toString());
+ descriptionGenerator.writePace(1.1, builder, R.string.description_average_pace, "\n");
+ assertEquals("Average pace: 15:09 min/km (24:23 min/mi)\n", builder.toString());
}
/**
@@ -197,18 +196,4 @@ public class DescriptionGeneratorImplTest extends AndroidTestCase {
Double.POSITIVE_INFINITY, builder, R.string.description_max_grade, "
");
assertEquals("Max grade: 0 %
", builder.toString());
}
-
- /**
- * Tests {@link DescriptionGeneratorImpl#getPace(double)}.
- */
- public void testGetPace() {
- assertEquals(12.0, descriptionGenerator.getPace(5));
- }
-
- /**
- * Tests {@link DescriptionGeneratorImpl#getPace(double)} with zero speed.
- */
- public void testGetPace_zero() {
- assertEquals(0.0, descriptionGenerator.getPace(0));
- }
}