From 9859e4ff14ae92b358681fdf45e6553cfe920183 Mon Sep 17 00:00:00 2001 From: youtaol Date: Fri, 24 Aug 2012 12:42:57 +0800 Subject: [PATCH] Merge heads --- MyTracks/res/values/strings.xml | 9 +- .../apps/mytracks/content/TrackDataHub.java | 19 +- .../mytracks/content/TrackDataListener.java | 13 +- .../mytracks/fragments/ChartFragment.java | 179 ++++++++---------- .../apps/mytracks/fragments/MapFragment.java | 127 +++++++------ .../mytracks/fragments/StatsFragment.java | 12 +- .../SendFusionTablesAsyncTask.java | 80 ++++---- .../mytracks/io/maps/SendMapsAsyncTask.java | 114 +++++------ .../services/TrackRecordingService.java | 6 +- .../mytracks/stats/TripStatisticsBuilder.java | 18 +- .../apps/mytracks/util/ChartURLGenerator.java | 72 +++---- .../android/apps/mytracks/TrackStubUtils.java | 3 +- .../mytracks/content/TrackDataHubTest.java | 10 +- .../mytracks/fragments/ChartFragmentTest.java | 56 ++++-- 14 files changed, 373 insertions(+), 345 deletions(-) diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml index 6600757f7..0e681478f 100644 --- a/MyTracks/res/values/strings.xml +++ b/MyTracks/res/values/strings.xml @@ -683,12 +683,17 @@ limitations under the License. translation_description="On application start, message when there is no GPS on the device."> No GPS is found on the device. - Waiting for a better GPS signal. Make sure the sky is visible. - + + Waiting for GPS signal. Make sure the sky is visible. + + pendingPoints = new ArrayList(); - + private TrackDataHub trackDataHub; // Stats gathered from the received data - private double totalDistance = 0.0; - private long startTime = -1L; - private Location lastLocation = null; - private double trackMaxSpeed = 0.0; + private TripStatisticsBuilder tripStatisticsBuilder; + private long startTime; + + private boolean metricUnits = PreferencesUtils.METRIC_UNITS_DEFAULT; + private boolean reportSpeed = PreferencesUtils.REPORT_SPEED_DEFAULT; + private int minRecordingDistance = PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT; // Modes of operation - private boolean metricUnits = true; - private boolean reportSpeed = true; - private boolean chartByDistance = true; - private boolean[] chartShow = new boolean[] {true, true, true, true, true, true}; + private boolean[] chartShow = new boolean[] { true, true, true, true, true, true }; // UI elements private ChartView chartView; @@ -88,7 +81,7 @@ public class ChartFragment extends Fragment implements TrackDataListener { * appropriate and redraw. */ private final Runnable updateChart = new Runnable() { - @Override + @Override public void run() { if (trackDataHub == null) { return; @@ -118,13 +111,13 @@ public class ChartFragment extends Fragment implements TrackDataListener { View view = inflater.inflate(R.layout.chart, container, false); zoomControls = (ZoomControls) view.findViewById(R.id.chart_zoom_controls); zoomControls.setOnZoomInClickListener(new View.OnClickListener() { - @Override + @Override public void onClick(View v) { zoomIn(); } }); zoomControls.setOnZoomOutClickListener(new View.OnClickListener() { - @Override + @Override public void onClick(View v) { zoomOut(); } @@ -141,7 +134,7 @@ public class ChartFragment extends Fragment implements TrackDataListener { LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); layout.addView(chartView, layoutParams); } - + @Override public void onResume() { super.onResume(); @@ -186,26 +179,20 @@ public class ChartFragment extends Fragment implements TrackDataListener { @Override public void onTrackUpdated(Track track) { if (track == null || track.getTripStatistics() == null) { - trackMaxSpeed = 0.0; + startTime = -1L; return; } - trackMaxSpeed = track.getTripStatistics().getMaxSpeed(); + startTime = track.getTripStatistics().getStartTime(); } @Override public void clearTrackPoints() { - totalDistance = 0.0; - startTime = -1L; - lastLocation = null; - - elevationBuffer.reset(); - speedBuffer.reset(); + tripStatisticsBuilder = startTime != -1L ? new TripStatisticsBuilder(startTime) : null; pendingPoints.clear(); - chartView.reset(); getActivity().runOnUiThread(new Runnable() { - @Override + @Override public void run() { chartView.resetScroll(); } @@ -214,24 +201,19 @@ public class ChartFragment extends Fragment implements TrackDataListener { @Override public void onSampledInTrackPoint(Location location) { - if (LocationUtils.isValidLocation(location)) { - double[] data = new double[ChartView.NUM_SERIES + 1]; - fillDataPoint(location, data); - pendingPoints.add(data); - } + double[] data = new double[ChartView.NUM_SERIES + 1]; + fillDataPoint(location, data); + pendingPoints.add(data); } @Override public void onSampledOutTrackPoint(Location location) { - if (LocationUtils.isValidLocation(location)) { - // Still account for the point in the smoothing buffers. - fillDataPoint(location, null); - } + fillDataPoint(location, null); } @Override - public void onSegmentSplit() { - // Do nothing. + public void onSegmentSplit(Location location) { + fillDataPoint(location, null); } @Override @@ -266,7 +248,7 @@ public class ChartFragment extends Fragment implements TrackDataListener { metricUnits = metric; chartView.setMetricUnits(metricUnits); getActivity().runOnUiThread(new Runnable() { - @Override + @Override public void run() { chartView.requestLayout(); } @@ -286,7 +268,7 @@ public class ChartFragment extends Fragment implements TrackDataListener { setSeriesEnabled(ChartView.SPEED_SERIES, chartShowSpeed && reportSpeed); setSeriesEnabled(ChartView.PACE_SERIES, chartShowSpeed && !reportSpeed); getActivity().runOnUiThread(new Runnable() { - @Override + @Override public void run() { chartView.requestLayout(); } @@ -294,6 +276,15 @@ public class ChartFragment extends Fragment implements TrackDataListener { return true; } + @Override + public boolean onMinRecordingDistanceChanged(int value) { + if (minRecordingDistance == value) { + return false; + } + minRecordingDistance = value; + return true; + } + /** * Checks the chart settings. */ @@ -310,7 +301,7 @@ public class ChartFragment extends Fragment implements TrackDataListener { R.string.chart_show_elevation_key, PreferencesUtils.CHART_SHOW_ELEVATION_DEFAULT))) { needUpdate = true; } - + boolean chartShowSpeed = PreferencesUtils.getBoolean( getActivity(), R.string.chart_show_speed_key, PreferencesUtils.CHART_SHOW_SPEED_DEFAULT); if (setSeriesEnabled(ChartView.SPEED_SERIES, chartShowSpeed && reportSpeed)) { @@ -354,17 +345,14 @@ public class ChartFragment extends Fragment implements TrackDataListener { } /** - * Resumes the trackDataHub. Needs to be synchronized because trackDataHub can be - * accessed by multiple threads. + * Resumes the trackDataHub. Needs to be synchronized because trackDataHub can + * be accessed by multiple threads. */ private synchronized void resumeTrackDataHub() { trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub(); - trackDataHub.registerTrackDataListener(this, EnumSet.of( - TrackDataType.SELECTED_TRACK, - TrackDataType.TRACKS_TABLE, - TrackDataType.WAYPOINTS_TABLE, - TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE, - TrackDataType.SAMPLED_OUT_TRACK_POINTS_TABLE, + trackDataHub.registerTrackDataListener(this, EnumSet.of(TrackDataType.SELECTED_TRACK, + TrackDataType.TRACKS_TABLE, TrackDataType.WAYPOINTS_TABLE, + TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE, TrackDataType.SAMPLED_OUT_TRACK_POINTS_TABLE, TrackDataType.PREFERENCE)); } @@ -386,15 +374,15 @@ public class ChartFragment extends Fragment implements TrackDataListener { } /** - * Reloads the trackDataHub. Needs to be synchronized because trackDataHub can be - * accessed by multiple threads. + * Reloads the trackDataHub. Needs to be synchronized because trackDataHub can + * be accessed by multiple threads. */ private synchronized void reloadTrackDataHub() { if (trackDataHub != null) { trackDataHub.reloadDataForListener(this); } } - + /** * To zoom in. */ @@ -412,7 +400,7 @@ public class ChartFragment extends Fragment implements TrackDataListener { zoomControls.setIsZoomInEnabled(chartView.canZoomIn()); zoomControls.setIsZoomOutEnabled(chartView.canZoomOut()); } - + /** * Given a location, fill in a data point, an array of double[].
* data[0] = time/distance
@@ -435,44 +423,31 @@ public class ChartFragment extends Fragment implements TrackDataListener { double heartRate = Double.NaN; double cadence = Double.NaN; double power = Double.NaN; - - // TODO: Use TripStatisticsBuilder - if (chartByDistance) { - if (lastLocation != null) { - double distance = lastLocation.distanceTo(location) * UnitConversions.M_TO_KM; - if (metricUnits) { - totalDistance += distance; - } else { - totalDistance += distance * UnitConversions.KM_TO_MI; - } - } - timeOrDistance = totalDistance; - } else { - if (startTime == -1L) { - startTime = location.getTime(); - } - timeOrDistance = location.getTime() - startTime; - } - - elevationBuffer.setNext(metricUnits ? location.getAltitude() : location.getAltitude() - * UnitConversions.M_TO_FT); - elevation = elevationBuffer.getAverage(); - - if (lastLocation == null) { - if (Math.abs(location.getSpeed() - INVALID_SPEED) > 1) { - speedBuffer.setNext(location.getSpeed()); - } - } else if (TripStatisticsBuilder.isValidSpeed(location.getTime(), location.getSpeed(), - lastLocation.getTime(), lastLocation.getSpeed(), speedBuffer) - && (location.getSpeed() <= trackMaxSpeed)) { - speedBuffer.setNext(location.getSpeed()); - } - speed = speedBuffer.getAverage() * UnitConversions.MS_TO_KMH; - if (!metricUnits) { - speed *= UnitConversions.KM_TO_MI; - } - pace = speed == 0 ? 0.0 : 60.0 / speed; + if (tripStatisticsBuilder != null) { + tripStatisticsBuilder.addLocation(location, minRecordingDistance); + TripStatistics tripStatistics = tripStatisticsBuilder.getTripStatistics(); + if (chartByDistance) { + double distance = tripStatistics.getTotalDistance() * UnitConversions.M_TO_KM; + if (!metricUnits) { + distance *= UnitConversions.KM_TO_MI; + } + timeOrDistance = distance; + } else { + timeOrDistance = tripStatistics.getTotalTime(); + } + + elevation = tripStatisticsBuilder.getSmoothedElevation(); + if (!metricUnits) { + elevation *= UnitConversions.M_TO_FT; + } + + speed = tripStatisticsBuilder.getSmoothedSpeed() * UnitConversions.MS_TO_KMH; + if (!metricUnits) { + speed *= UnitConversions.KM_TO_MI; + } + pace = speed == 0 ? 0.0 : 60.0 / speed; + } if (location instanceof MyTracksLocation && ((MyTracksLocation) location).getSensorDataSet() != null) { SensorDataSet sensorDataSet = ((MyTracksLocation) location).getSensorDataSet(); @@ -502,7 +477,6 @@ public class ChartFragment extends Fragment implements TrackDataListener { data[5] = cadence; data[6] = power; } - lastLocation = location; } @VisibleForTesting @@ -510,25 +484,26 @@ public class ChartFragment extends Fragment implements TrackDataListener { return chartView; } + @VisibleForTesting + void setTripStatisticsBuilder(long time) { + tripStatisticsBuilder = new TripStatisticsBuilder(time); + } + @VisibleForTesting void setChartView(ChartView view) { chartView = view; } - - @VisibleForTesting - void setTrackMaxSpeed(double value) { - trackMaxSpeed = value; - } - + @VisibleForTesting void setMetricUnits(boolean value) { metricUnits = value; } - + @VisibleForTesting void setReportSpeed(boolean value) { reportSpeed = value; } + @VisibleForTesting void setChartByDistance(boolean value) { chartByDistance = value; diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/MapFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/MapFragment.java index 35d35bca3..984a463cc 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/MapFragment.java +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/MapFragment.java @@ -57,7 +57,7 @@ import java.util.List; /** * A fragment to display map to the user. - * + * * @author Leif Hendrik Wilden * @author Rodrigo Damazio */ @@ -65,7 +65,7 @@ public class MapFragment extends Fragment implements View.OnTouchListener, View.OnClickListener, TrackDataListener { public static final String MAP_FRAGMENT_TAG = "mapFragment"; - + private static final String KEY_CURRENT_LOCATION = "currentLocation"; private static final String KEY_KEEP_MY_LOCATION_VISIBLE = "keepMyLocationVisible"; @@ -108,19 +108,19 @@ public class MapFragment extends Fragment mapViewContainer = ((TrackDetailActivity) getActivity()).getMapViewContainer(); mapView = (MapView) mapViewContainer.findViewById(R.id.map_view); mapOverlay = new MapOverlay(getActivity()); - + List overlays = mapView.getOverlays(); overlays.clear(); overlays.add(mapOverlay); - + mapView.requestFocus(); mapView.setOnTouchListener(this); mapView.setBuiltInZoomControls(true); myLocationImageButton = (ImageButton) mapViewContainer.findViewById(R.id.map_my_location); myLocationImageButton.setOnClickListener(new View.OnClickListener() { - @Override + @Override public void onClick(View v) { - showMyLocation(); + showMyLocation(); } }); messageTextView = (TextView) mapViewContainer.findViewById(R.id.map_message); @@ -227,7 +227,7 @@ public class MapFragment extends Fragment /** * Shows the marker. - * + * * @param trackId the track id * @param id the marker id */ @@ -277,29 +277,36 @@ public class MapFragment extends Fragment public void onLocationStateChanged(LocationState state) { final String message; final boolean isGpsDisabled; - switch (state) { - case DISABLED: - String setting = getString( - GoogleLocationUtils.isAvailable(getActivity()) ? R.string.gps_google_location_settings - : R.string.gps_location_access); - message = getString(R.string.gps_disabled, setting); - isGpsDisabled = true; - break; - case NO_FIX: - case BAD_FIX: - message = getString(R.string.gps_wait_for_signal); - isGpsDisabled = false; - break; - case GOOD_FIX: - message = null; - isGpsDisabled = false; - break; - default: - throw new IllegalArgumentException("Unexpected state: " + state); + if (!isSelectedTrackRecording()) { + message = null; + isGpsDisabled = false; + } else { + switch (state) { + case DISABLED: + String setting = getString( + GoogleLocationUtils.isAvailable(getActivity()) ? R.string.gps_google_location_settings + : R.string.gps_location_access); + message = getString(R.string.gps_disabled, setting); + isGpsDisabled = true; + break; + case NO_FIX: + message = getString(R.string.gps_wait_for_signal); + isGpsDisabled = false; + break; + case BAD_FIX: + message = getString(R.string.gps_wait_for_better_signal); + isGpsDisabled = false; + break; + case GOOD_FIX: + message = null; + isGpsDisabled = false; + break; + default: + throw new IllegalArgumentException("Unexpected state: " + state); + } } - getActivity().runOnUiThread(new Runnable() { - @Override + @Override public void run() { if (message != null) { messageTextView.setText(message); @@ -336,12 +343,12 @@ public class MapFragment extends Fragment @Override public void onSelectedTrackChanged(final Track track) { getActivity().runOnUiThread(new Runnable() { - @Override + @Override public void run() { boolean hasTrack = track != null; mapOverlay.setTrackDrawingEnabled(hasTrack); - - if (hasTrack) { + + if (hasTrack) { synchronized (this) { /* * Synchronize to prevent race condition in changing markerTrackId @@ -369,18 +376,16 @@ public class MapFragment extends Fragment @Override public void onSampledInTrackPoint(Location location) { - if (LocationUtils.isValidLocation(location)) { - mapOverlay.addLocation(location); - } + mapOverlay.addLocation(location); } @Override - public void onSampledOutTrackPoint(Location loc) { + public void onSampledOutTrackPoint(Location location) { // We don't care. } @Override - public void onSegmentSplit() { + public void onSegmentSplit(Location location) { mapOverlay.addSegmentSplit(); } @@ -418,24 +423,27 @@ public class MapFragment extends Fragment // We don't care. return false; } - + + @Override + public boolean onMinRecordingDistanceChanged(int minRecordingDistance) { + // We don't care. + return false; + } + /** - * Resumes the trackDataHub. Needs to be synchronized because trackDataHub can be - * accessed by multiple threads. + * Resumes the trackDataHub. Needs to be synchronized because trackDataHub can + * be accessed by multiple threads. */ private synchronized void resumeTrackDataHub() { trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub(); - trackDataHub.registerTrackDataListener(this, EnumSet.of( - TrackDataType.SELECTED_TRACK, - TrackDataType.WAYPOINTS_TABLE, - TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE, - TrackDataType.LOCATION, - TrackDataType.HEADING)); + trackDataHub.registerTrackDataListener(this, EnumSet.of(TrackDataType.SELECTED_TRACK, + TrackDataType.WAYPOINTS_TABLE, TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE, + TrackDataType.LOCATION, TrackDataType.HEADING)); } - + /** - * Pauses the trackDataHub. Needs to be synchronized because trackDataHub can be - * accessed by multiple threads. + * Pauses the trackDataHub. Needs to be synchronized because trackDataHub can + * be accessed by multiple threads. */ private synchronized void pauseTrackDataHub() { trackDataHub.unregisterTrackDataListener(this); @@ -443,15 +451,15 @@ public class MapFragment extends Fragment } /** - * Updates the trackDataHub. Needs to be synchronized because trackDataHub can be - * accessed by multiple threads. + * Updates the trackDataHub. Needs to be synchronized because trackDataHub can + * be accessed by multiple threads. */ private synchronized void updateTrackDataHub() { if (trackDataHub != null) { trackDataHub.forceUpdateLocation(); } } - + /** * Returns true if the selected track is recording. Needs to be synchronized * because trackDataHub can be accessed by multiple threads. @@ -461,8 +469,9 @@ public class MapFragment extends Fragment } /** - * Updates the map by either zooming to the requested marker or showing the track. - * + * Updates the map by either zooming to the requested marker or showing the + * track. + * * @param track the track */ private void updateMap(Track track) { @@ -480,7 +489,7 @@ public class MapFragment extends Fragment /** * Returns true if the location is visible. - * + * * @param location the location */ private boolean isVisible(Location location) { @@ -490,7 +499,7 @@ public class MapFragment extends Fragment GeoPoint mapCenter = mapView.getMapCenter(); int latitudeSpan = mapView.getLatitudeSpan(); int longitudeSpan = mapView.getLongitudeSpan(); - + /* * The bottom of the mapView is obscured by the zoom controls, subtract its * height from the visible area. @@ -498,11 +507,11 @@ public class MapFragment extends Fragment GeoPoint zoomControlBottom = mapView.getProjection().fromPixels(0, mapView.getHeight()); GeoPoint zoomControlTop = mapView.getProjection().fromPixels( 0, mapView.getHeight() - mapView.getZoomButtonsController().getZoomControls().getHeight()); - int zoomControlMargin = Math.abs(zoomControlTop.getLatitudeE6() - - zoomControlBottom.getLatitudeE6()); + int zoomControlMargin = Math.abs( + zoomControlTop.getLatitudeE6() - zoomControlBottom.getLatitudeE6()); GeoRect geoRect = new GeoRect(mapCenter, latitudeSpan, longitudeSpan); geoRect.top += zoomControlMargin; - + GeoPoint geoPoint = LocationUtils.getGeoPoint(location); return geoRect.contains(geoPoint); } @@ -534,7 +543,7 @@ public class MapFragment extends Fragment /** * Shows the track. - * + * * @param track the track */ private void showTrack(Track track) { diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/StatsFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/StatsFragment.java index 1e11174f1..0e7dcd0c7 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/StatsFragment.java +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/StatsFragment.java @@ -186,17 +186,17 @@ public class StatsFragment extends Fragment implements TrackDataListener { } @Override - public void onSampledInTrackPoint(Location loc) { + public void onSampledInTrackPoint(Location location) { // We don't care. } @Override - public void onSampledOutTrackPoint(Location loc) { + public void onSampledOutTrackPoint(Location location) { // We don't care. } @Override - public void onSegmentSplit() { + public void onSegmentSplit(Location location) { // We don't care. } @@ -246,6 +246,12 @@ public class StatsFragment extends Fragment implements TrackDataListener { return true; } + @Override + public boolean onMinRecordingDistanceChanged(int minRecordingDistance) { + // We don't care. + return false; + } + /** * Resumes the trackDataHub. Needs to be synchronized because trackDataHub can * be accessed by multiple threads. 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 27373ae72..0afa56da0 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 @@ -10,13 +10,11 @@ import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask; import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils; -import com.google.android.apps.mytracks.stats.DoubleBuffer; import com.google.android.apps.mytracks.stats.TripStatisticsBuilder; import com.google.android.apps.mytracks.util.ApiAdapterFactory; import com.google.android.apps.mytracks.util.LocationUtils; import com.google.android.apps.mytracks.util.PreferencesUtils; import com.google.android.apps.mytracks.util.SystemUtils; -import com.google.android.apps.mytracks.util.UnitConversions; import com.google.android.maps.mytracks.R; import com.google.api.client.googleapis.GoogleHeaders; import com.google.api.client.googleapis.MethodOverride; @@ -48,7 +46,7 @@ import java.util.Vector; /** * AsyncTask to send a track to Google Fusion Tables. - * + * * @author Jimmy Shih */ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { @@ -59,8 +57,8 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { @VisibleForTesting public static final String CONTENT_TYPE = "application/x-www-form-urlencoded"; @VisibleForTesting - public static final String FUSION_TABLES_BASE_URL = - "https://www.google.com/fusiontables/api/query"; + public static final String + FUSION_TABLES_BASE_URL = "https://www.google.com/fusiontables/api/query"; private static final int MAX_POINTS_PER_UPLOAD = 2048; @VisibleForTesting public static final String GDATA_VERSION = "2"; @@ -72,14 +70,15 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { private static final int PROGRESS_UPLOAD_WAYPOINTS = 95; private static final int PROGRESS_COMPLETE = 100; - // See http://support.google.com/fusiontables/bin/answer.py?hl=en&answer=185991 + // See + // http://support.google.com/fusiontables/bin/answer.py?hl=en&answer=185991 private static final String MARKER_TYPE_START = "large_green"; private static final String MARKER_TYPE_END = "large_red"; private static final String MARKER_TYPE_WAYPOINT = "large_blue"; private static final String MARKER_TYPE_STATISTICS = "large_yellow"; - + private static final String TAG = SendFusionTablesAsyncTask.class.getSimpleName(); - + private final Context context; private final long trackId; private final Account account; @@ -127,8 +126,8 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { currentSegment = 1; try { - authToken = AccountManager.get(context).blockingGetAuthToken( - account, SendFusionTablesUtils.SERVICE, false); + authToken = AccountManager.get(context) + .blockingGetAuthToken(account, SendFusionTablesUtils.SERVICE, false); } catch (OperationCanceledException e) { Log.d(TAG, "Unable to get auth token", e); return retryTask(); @@ -182,7 +181,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { /** * Creates a new table. - * + * * @param track the track * @return true if success. */ @@ -194,7 +193,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { /** * Unlists a table. - * + * * @return true if success. */ private boolean unlistTable() { @@ -204,32 +203,31 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { /** * Uploads all the points in a track. - * + * * @param track the track * @return true if success. */ private boolean uploadAllTrackPoints(Track track) { Cursor locationsCursor = null; try { - boolean metricUnits = PreferencesUtils.getBoolean( - context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT); - locationsCursor = myTracksProviderUtils.getLocationsCursor(trackId, 0, -1, false); if (locationsCursor == null) { Log.d(TAG, "Location cursor is null"); return false; } + int locationsCount = locationsCursor.getCount(); List locations = new ArrayList(MAX_POINTS_PER_UPLOAD); Location lastLocation = null; // For chart server, limit the number of elevation readings to 250. int elevationSamplingFrequency = Math.max(1, (int) (locationsCount / 250.0)); - TripStatisticsBuilder tripStatisticsBuilder = new TripStatisticsBuilder( - track.getTripStatistics().getStartTime()); - DoubleBuffer elevationBuffer = new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR); Vector distances = new Vector(); Vector elevations = new Vector(); + TripStatisticsBuilder tripStatisticsBuilder = new TripStatisticsBuilder( + track.getTripStatistics().getStartTime()); + int minRecordingDistance = PreferencesUtils.getInt(context, + R.string.min_recording_distance_key, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT); for (int i = 0; i < locationsCount; i++) { locationsCursor.moveToPosition(i); @@ -246,16 +244,12 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { } } - // Add to the distances and elevations vectors + tripStatisticsBuilder.addLocation(location, minRecordingDistance); + if (i % elevationSamplingFrequency == 0) { + distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance()); + elevations.add(tripStatisticsBuilder.getSmoothedElevation()); + } if (LocationUtils.isValidLocation(location)) { - tripStatisticsBuilder.addLocation(location, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT); - // All points go into the smoothing buffer - elevationBuffer.setNext(metricUnits ? location.getAltitude() - : location.getAltitude() * UnitConversions.M_TO_FT); - if (i % elevationSamplingFrequency == 0) { - distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance()); - elevations.add(elevationBuffer.getAverage()); - } lastLocation = location; } @@ -280,7 +274,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { // Create an end marker if (lastLocation != null) { distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance()); - elevations.add(elevationBuffer.getAverage()); + elevations.add(tripStatisticsBuilder.getSmoothedElevation()); DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context); track.setDescription( descriptionGenerator.generateTrackDescription(track, distances, elevations, true)); @@ -301,7 +295,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { /** * Prepares and uploads a list of locations from a track. - * + * * @param track the track * @param locations the locations from the track * @param lastBatch true if it is the last batch of locations @@ -328,7 +322,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { /** * Uploads all the waypoints. - * + * * @return true if success. */ private boolean uploadWaypoints() { @@ -358,17 +352,15 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { } /** - * Creates a new row in Google Fusion Tables representing a marker as a - * point. - * + * Creates a new row in Google Fusion Tables representing a marker as a point. + * * @param name the marker name * @param description the marker description * @param location the marker location * @param type the marker type * @return true if success. */ - private boolean createNewPoint( - String name, String description, Location location, String type) { + private boolean createNewPoint(String name, String description, Location location, String type) { String query = "INSERT INTO " + tableId + " (name,description,geometry,marker) VALUES " + SendFusionTablesUtils.formatSqlValues( name, description, SendFusionTablesUtils.getKmlPoint(location), type); @@ -376,22 +368,23 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { } /** - * Creates a new row in Google Fusion Tables representing the track as a - * line segment. - * + * Creates a new row in Google Fusion Tables representing the track as a line + * segment. + * * @param track the track * @return true if success. */ private boolean createNewLineString(Track track) { - String query = "INSERT INTO " + tableId + " (name,description,geometry) VALUES " - + SendFusionTablesUtils.formatSqlValues(track.getName(), track.getDescription(), + String query = "INSERT INTO " + tableId + + " (name,description,geometry) VALUES " + SendFusionTablesUtils.formatSqlValues( + track.getName(), track.getDescription(), SendFusionTablesUtils.getKmlLineString(track.getLocations())); return sendQuery(query, false); } /** * Sends a query to Google Fusion Tables. - * + * * @param query the Fusion Tables SQL query * @param setTableId true to set the table id * @return true if success. @@ -463,7 +456,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { /** * Updates the progress based on the number of locations uploaded. - * + * * @param uploaded the number of uploaded locations * @param total the number of total locations */ @@ -474,4 +467,3 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { publishProgress((int) scaledPercentage); } } - 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 65048d74f..5e00b08f0 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 @@ -28,11 +28,9 @@ import com.google.android.apps.mytracks.io.gdata.maps.MapsGDataConverter; import com.google.android.apps.mytracks.io.gdata.maps.XmlMapsGDataParserFactory; import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask; import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils; -import com.google.android.apps.mytracks.stats.DoubleBuffer; import com.google.android.apps.mytracks.stats.TripStatisticsBuilder; import com.google.android.apps.mytracks.util.LocationUtils; import com.google.android.apps.mytracks.util.PreferencesUtils; -import com.google.android.apps.mytracks.util.UnitConversions; import com.google.android.common.gdata.AndroidXmlParserFactory; import com.google.android.maps.mytracks.R; import com.google.common.annotations.VisibleForTesting; @@ -63,14 +61,14 @@ import org.xmlpull.v1.XmlPullParserException; * the Google Maps servers through this API is only allowed for the My Tracks * application. Other applications looking to upload maps data should look into * using the Google Fusion Tables API. - * + * * @author Jimmy Shih */ public class SendMapsAsyncTask extends AbstractSendAsyncTask { - private static final String START_ICON_URL = - "http://maps.google.com/mapfiles/ms/micons/green-dot.png"; - private static final String END_ICON_URL = - "http://maps.google.com/mapfiles/ms/micons/red-dot.png"; + private static final String + START_ICON_URL = "http://maps.google.com/mapfiles/ms/micons/green-dot.png"; + private static final String + END_ICON_URL = "http://maps.google.com/mapfiles/ms/micons/red-dot.png"; private static final int MAX_POINTS_PER_UPLOAD = 500; private static final int PROGRESS_FETCH_MAP_ID = 5; @@ -97,25 +95,25 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { private String mapId; int currentSegment; - public SendMapsAsyncTask(SendMapsActivity activity, long trackId, Account account, - String chooseMapId) { - this(activity, trackId, account, chooseMapId, MyTracksProviderUtils.Factory.get(activity - .getApplicationContext())); + public SendMapsAsyncTask( + SendMapsActivity activity, long trackId, Account account, String chooseMapId) { + this(activity, trackId, account, chooseMapId, MyTracksProviderUtils.Factory.get( + activity.getApplicationContext())); } - + /** * This constructor is created for test. */ @VisibleForTesting - public SendMapsAsyncTask ( - SendMapsActivity activity, long trackId, Account account, String chooseMapId, MyTracksProviderUtils myTracksProviderUtils) { + public SendMapsAsyncTask(SendMapsActivity activity, long trackId, Account account, + String chooseMapId, MyTracksProviderUtils myTracksProviderUtils) { super(activity); this.trackId = trackId; this.account = account; this.chooseMapId = chooseMapId; this.myTracksProviderUtils = myTracksProviderUtils; context = activity.getApplicationContext(); - + gDataClient = GDataClientFactory.getGDataClient(context); mapsClient = new MapsClient( gDataClient, new XmlMapsGDataParserFactory(new AndroidXmlParserFactory())); @@ -154,11 +152,11 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { Log.d(TAG, "Unable to create a maps gdata converter", e); return false; } - + // Get auth token try { - authToken = AccountManager.get(context).blockingGetAuthToken( - account, MapsConstants.SERVICE_NAME, false); + authToken = AccountManager.get(context) + .blockingGetAuthToken(account, MapsConstants.SERVICE_NAME, false); } catch (OperationCanceledException e) { Log.d(TAG, "Unable to get auth token", e); return retryTask(); @@ -208,9 +206,9 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { } /** - * Fetches the {@link SendMapsAsyncTask#mapId} instance variable for - * sending a track to Google Maps. - * + * Fetches the {@link SendMapsAsyncTask#mapId} instance variable for sending a + * track to Google Maps. + * * @param track the Track * @return true if able to fetch the mapId variable. */ @@ -219,7 +217,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { if (isCancelled()) { return false; } - + if (chooseMapId != null) { mapId = chooseMapId; return true; @@ -247,7 +245,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { /** * Uploads all the points in a track. - * + * * @param track the track * @return true if success. */ @@ -255,25 +253,24 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { boolean uploadAllTrackPoints(Track track) { Cursor locationsCursor = null; try { - boolean metricUnits = PreferencesUtils.getBoolean( - context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT); - locationsCursor = myTracksProviderUtils.getLocationsCursor(trackId, 0, -1, false); if (locationsCursor == null) { Log.d(TAG, "Location cursor is null"); return false; } + int locationsCount = locationsCursor.getCount(); List locations = new ArrayList(MAX_POINTS_PER_UPLOAD); Location lastLocation = null; // For chart server, limit the number of elevation readings to 250. int elevationSamplingFrequency = Math.max(1, (int) (locationsCount / 250.0)); - TripStatisticsBuilder tripStatisticsBuilder = new TripStatisticsBuilder( - track.getTripStatistics().getStartTime()); - DoubleBuffer elevationBuffer = new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR); Vector distances = new Vector(); Vector elevations = new Vector(); + TripStatisticsBuilder tripStatisticsBuilder = new TripStatisticsBuilder( + track.getTripStatistics().getStartTime()); + int minRecordingDistance = PreferencesUtils.getInt(context, + R.string.min_recording_distance_key, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT); for (int i = 0; i < locationsCount; i++) { locationsCursor.moveToPosition(i); @@ -290,16 +287,12 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { } } - // Add to the distances and elevations vectors + tripStatisticsBuilder.addLocation(location, minRecordingDistance); + if (i % elevationSamplingFrequency == 0) { + distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance()); + elevations.add(tripStatisticsBuilder.getSmoothedElevation()); + } if (LocationUtils.isValidLocation(location)) { - tripStatisticsBuilder.addLocation(location, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT); - // All points go into the smoothing buffer - elevationBuffer.setNext(metricUnits ? location.getAltitude() - : location.getAltitude() * UnitConversions.M_TO_FT); - if (i % elevationSamplingFrequency == 0) { - distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance()); - elevations.add(elevationBuffer.getAverage()); - } lastLocation = location; } @@ -324,9 +317,10 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { // Create an end marker if (lastLocation != null) { distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance()); - elevations.add(elevationBuffer.getAverage()); - - track.setDescription(getTrackDescription(track, distances, elevations)); + elevations.add(tripStatisticsBuilder.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)) { Log.d(TAG, "Unable to create an end marker"); @@ -340,26 +334,10 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { } } } - - /** - * Gets the description of a track. - * - * @param track the track - * @param distances distance vectors - * @param elevations elevation vectors - * @return the description of a track. - */ - @VisibleForTesting - String getTrackDescription(Track track, Vector distances, Vector elevations) { - DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context); - return "

" + track.getDescription() + "

" - + descriptionGenerator.generateTrackDescription(track, distances, elevations, true) - + "

"; - } - + /** * Prepares and uploads a list of locations from a track. - * + * * @param track the track * @param locations the locations from the track * @param lastBatch true if it is the last batch of locations @@ -396,8 +374,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { * @return true if success. */ @VisibleForTesting - boolean uploadMarker( - String title, String description, String iconUrl, Location location) { + boolean uploadMarker(String title, String description, String iconUrl, Location location) { if (isCancelled()) { return false; } @@ -449,10 +426,10 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { } return true; } - + /** * Uploads all the waypoints. - * + * * @return true if success. */ @VisibleForTesting @@ -497,7 +474,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { /** * Updates the progress based on the number of locations uploaded. - * + * * @param uploaded the number of uploaded locations * @param total the number of total locations */ @@ -505,11 +482,10 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { void updateProgress(int uploaded, int total) { publishProgress(getPercentage(uploaded, total)); } - - + /** * Count the percentage of the number of locations uploaded. - * + * * @param uploaded the number of uploaded locations * @param total the number of total locations */ @@ -520,7 +496,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { * (PROGRESS_UPLOAD_DATA_MAX - PROGRESS_UPLOAD_DATA_MIN) + PROGRESS_UPLOAD_DATA_MIN; return (int) scaledPercentage; } - + /** * Gets the mapID. * @@ -530,7 +506,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { String getMapId() { return mapId; } - + /** * Sets the value of mapsGDataConverter. * 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 d810aedf2..c842ad76e 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java @@ -285,7 +285,7 @@ public class TrackRecordingService extends Service { // Require announcementExecutor and splitExecutor to be created. sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null); - timer.schedule(checkLocationListener, 5 * ONE_MINUTE, ONE_MINUTE); + timer.schedule(checkLocationListener, 0, ONE_MINUTE); /* * Try to restart the previous recording track in case the service has been @@ -843,7 +843,7 @@ public class TrackRecordingService extends Service { double distanceToLastTrackLocation = location.distanceTo(lastTrackLocation); if (distanceToLastTrackLocation < minRecordingDistance && sensorDataSet == null) { - // skip + Log.d(TAG, "Not recording location due to min recording distance."); } else if (distanceToLastTrackLocation > maxRecordingDistance) { insertLocation(track, lastLocation, lastTrackLocation); Location pause = new Location(LocationManager.GPS_PROVIDER); @@ -873,9 +873,11 @@ public class TrackRecordingService extends Service { private void insertLocation(Track track, Location location, Location lastRecordedLocation) { if (location == null) { + Log.w(TAG, "Ignore insertLocation. loation is null."); return; } if (location.equals(lastRecordedLocation)) { + Log.w(TAG, "Ignore insertLocation. loation same as last recorded location."); return; } diff --git a/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsBuilder.java b/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsBuilder.java index 1220c66e3..c9933becd 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsBuilder.java +++ b/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsBuilder.java @@ -145,11 +145,14 @@ public class TripStatisticsBuilder { * is noisy so the smoothed elevation is better than the raw elevation for * many tasks. */ - @VisibleForTesting - double getSmoothedElevation() { + public double getSmoothedElevation() { return elevationBuffer.getAverage(); } + public double getSmoothedSpeed() { + return speedBuffer.getAverage(); + } + /** * Updates a speed reading. Assumes the user is moving. * @@ -160,7 +163,7 @@ public class TripStatisticsBuilder { */ @VisibleForTesting void updateSpeed(long time, double speed, long lastLocationTime, double lastLocationSpeed) { - if (!isValidSpeed(time, speed, lastLocationTime, lastLocationSpeed, speedBuffer)) { + if (!isValidSpeed(time, speed, lastLocationTime, lastLocationSpeed)) { Log.d(TAG, "Invalid speed. speed: " + speed + " lastLocationSpeed: " + lastLocationSpeed); return; } @@ -168,10 +171,6 @@ public class TripStatisticsBuilder { if (speed > currentSegment.getMaxSpeed()) { currentSegment.setMaxSpeed(speed); } - double movingSpeed = currentSegment.getAverageMovingSpeed(); - if (speedBuffer.isFull() && movingSpeed > currentSegment.getMaxSpeed()) { - currentSegment.setMaxSpeed(movingSpeed); - } } /** @@ -229,10 +228,9 @@ public class TripStatisticsBuilder { * @param speed the speed * @param lastLocationTime the last location time * @param lastLocationSpeed the last location speed - * @param speedBuffer a buffer of speed readings */ - public static boolean isValidSpeed(long time, double speed, long lastLocationTime, - double lastLocationSpeed, DoubleBuffer speedBuffer) { + private boolean isValidSpeed( + long time, double speed, long lastLocationTime, double lastLocationSpeed) { /* * There are a lot of noisy speed readings. Do the cheapest checks first, diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/ChartURLGenerator.java b/MyTracks/src/com/google/android/apps/mytracks/util/ChartURLGenerator.java index 91f3a03cc..d345d1758 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/ChartURLGenerator.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/ChartURLGenerator.java @@ -19,6 +19,7 @@ package com.google.android.apps.mytracks.util; import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.maps.mytracks.R; +import com.google.common.annotations.VisibleForTesting; import android.content.Context; @@ -31,11 +32,9 @@ import java.util.Vector; */ public class ChartURLGenerator { - private static final String CHARTS_BASE_URL = - "http://chart.apis.google.com/chart?"; + private static final String CHARTS_BASE_URL = "http://chart.apis.google.com/chart?"; - private ChartURLGenerator() { - } + private ChartURLGenerator() {} /** * Gets a chart of a track. @@ -54,8 +53,7 @@ public class ChartURLGenerator { } /** - * Gets a chart of a track. - * This form is for testing without contexts. + * Gets a chart of a track. This form is for testing without contexts. * * @param distances An array of distance measurements * @param elevations A matching array of elevation measurements @@ -63,9 +61,9 @@ public class ChartURLGenerator { * @param title The title for the chart * @param metricUnits Should the data be displayed in metric units */ - public static String getChartUrl( - Vector distances, Vector elevations, - Track track, String title, boolean metricUnits) { + @VisibleForTesting + static String getChartUrl(Vector distances, Vector elevations, Track track, + String title, boolean metricUnits) { if (distances == null || elevations == null || track == null) { return null; } @@ -75,21 +73,23 @@ public class ChartURLGenerator { } // Round it up. - TripStatistics stats = track.getTripStatistics(); - double effectiveMaxY = metricUnits - ? stats.getMaxElevation() - : stats.getMaxElevation() * UnitConversions.M_TO_FT; + TripStatistics tripStatistics = track.getTripStatistics(); + double effectiveMaxY = tripStatistics.getMaxElevation(); + if (!metricUnits) { + effectiveMaxY *= UnitConversions.M_TO_FT; + } effectiveMaxY = ((int) (effectiveMaxY / 100)) * 100 + 100; - // Round it down. - double effectiveMinY = 0; - double minElevation = metricUnits - ? stats.getMinElevation() - : stats.getMinElevation() * UnitConversions.M_TO_FT; - effectiveMinY = ((int) (minElevation / 100)) * 100; - if (stats.getMinElevation() < 0) { + // Round it down. + double effectiveMinY = tripStatistics.getMinElevation(); + if (!metricUnits) { + effectiveMinY *= UnitConversions.M_TO_FT; + } + effectiveMinY = ((int) (effectiveMinY / 100)) * 100; + if (tripStatistics.getMinElevation() < 0) { effectiveMinY -= 100; } + double ySpread = effectiveMaxY - effectiveMinY; StringBuilder sb = new StringBuilder(CHARTS_BASE_URL); @@ -102,17 +102,18 @@ public class ChartURLGenerator { // Labels sb.append("&chxt=x,y"); - double distKM = stats.getTotalDistance() * UnitConversions.M_TO_KM; - double distDisplay = - metricUnits ? distKM : (distKM * UnitConversions.KM_TO_MI); - int xInterval = ((int) (distDisplay / 6)); + double totalDistance = tripStatistics.getTotalDistance() * UnitConversions.M_TO_KM; + if (!metricUnits) { + totalDistance *= UnitConversions.KM_TO_MI; + } + int xInterval = ((int) (totalDistance / 6)); int yInterval = ((int) (ySpread / 600)) * 100; if (yInterval < 100) { yInterval = 25; } // Range sb.append("&chxr=0,0,"); - sb.append((int) distDisplay); + sb.append((int) totalDistance); sb.append(','); sb.append(xInterval); @@ -138,28 +139,27 @@ public class ChartURLGenerator { // Data sb.append("&chd=e:"); for (int i = 0; i < distances.size(); i++) { - int normalized = - (int) (getNormalizedDistance(distances.elementAt(i), track) * 4095); + int normalized = (int) (getNormalizedDistance(distances.elementAt(i), track) * 4095); sb.append(ChartsExtendedEncoder.getEncodedValue(normalized)); } sb.append(ChartsExtendedEncoder.getSeparator()); for (int i = 0; i < elevations.size(); i++) { - int normalized = - (int) (getNormalizedElevation( - elevations.elementAt(i), effectiveMinY, ySpread) * 4095); + double value = elevations.elementAt(i); + if (!metricUnits) { + value *= UnitConversions.M_TO_FT; + } + int normalized = (int) (getNormalizedElevation(value, effectiveMinY, ySpread) * 4095); sb.append(ChartsExtendedEncoder.getEncodedValue(normalized)); } - return sb.toString(); } - private static double getNormalizedDistance(double d, Track track) { - return d / track.getTripStatistics().getTotalDistance(); + private static double getNormalizedDistance(double value, Track track) { + return value / track.getTripStatistics().getTotalDistance(); } - private static double getNormalizedElevation( - double d, double effectiveMinY, double ySpread) { - return (d - effectiveMinY) / ySpread; + private static double getNormalizedElevation(double value, double effectiveMinY, double ySpread) { + return (value - effectiveMinY) / ySpread; } } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/TrackStubUtils.java b/MyTracksTest/src/com/google/android/apps/mytracks/TrackStubUtils.java index 2fc915d7a..ea0ac573f 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/TrackStubUtils.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/TrackStubUtils.java @@ -36,6 +36,7 @@ public class TrackStubUtils { public static final double INITIAL_ALTITUDE = 22; static final float INITIAL_ACCURACY = 5; static final float INITIAL_SPEED = 10; + public static final long INITIAL_TIME = 1000L; static final float INITIAL_BEARING = 3.0f; // Used to change the value of latitude, longitude, and altitude. static final double DIFFERENCE = 0.01; @@ -79,7 +80,7 @@ public class TrackStubUtils { loc.setAltitude(altitude); loc.setAccuracy(INITIAL_ACCURACY); loc.setSpeed(INITIAL_SPEED); - loc.setTime(System.currentTimeMillis()); + loc.setTime(INITIAL_TIME); loc.setBearing(INITIAL_BEARING); SensorDataSet sd = SensorDataSet.newBuilder().build(); MyTracksLocation myTracksLocation = new MyTracksLocation(loc, sd); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/content/TrackDataHubTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/content/TrackDataHubTest.java index 4837b88a1..02c22558d 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/content/TrackDataHubTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/content/TrackDataHubTest.java @@ -613,12 +613,18 @@ public class TrackDataHubTest extends AndroidTestCase { // Register two listeners PreferencesUtils.setBoolean(context, R.string.report_speed_key, true); PreferencesUtils.setBoolean(context, R.string.metric_units_key, true); + PreferencesUtils.setInt(context, R.string.min_recording_distance_key, + PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT); dataSource.registerOnSharedPreferenceChangeListener(capture(preferenceChangeListenerCapture)); expect(trackDataListener1.onMetricUnitsChanged(true)).andReturn(false); expect(trackDataListener1.onReportSpeedChanged(true)).andReturn(false); + expect(trackDataListener1.onMinRecordingDistanceChanged( + PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT)).andReturn(false); expect(trackDataListener2.onMetricUnitsChanged(true)).andReturn(false); expect(trackDataListener2.onReportSpeedChanged(true)).andReturn(false); + expect(trackDataListener2.onMinRecordingDistanceChanged( + PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT)).andReturn(false); replay(); trackDataHub.start(); @@ -737,7 +743,7 @@ public class TrackDataHubTest extends AndroidTestCase { public void expectLocationsDelivered(TrackDataListener listener) { for (int i = 0; i < locations.length; i++) { if (splitIndexSet.contains(i)) { - listener.onSegmentSplit(); + listener.onSegmentSplit(locations[i]); } else { listener.onSampledInTrackPoint(locations[i]); } @@ -749,7 +755,7 @@ public class TrackDataHubTest extends AndroidTestCase { boolean includeNext = false; for (int i = 0; i < locations.length; i++) { if (splitIndexSet.contains(i)) { - listener.onSegmentSplit(); + listener.onSegmentSplit(locations[i]); includeNext = true; } else if (includeNext || (i % sampleFrequency == 0)) { listener.onSampledInTrackPoint(locations[i]); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/fragments/ChartFragmentTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/fragments/ChartFragmentTest.java index 4717e0ec9..4bc725754 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/fragments/ChartFragmentTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/fragments/ChartFragmentTest.java @@ -41,6 +41,7 @@ public class ChartFragmentTest extends AndroidTestCase { protected void setUp() throws Exception { chartFragment = new ChartFragment(); chartFragment.setChartView(new ChartView(getContext())); + chartFragment.setTripStatisticsBuilder(TrackStubUtils.INITIAL_TIME); } /** @@ -251,15 +252,12 @@ public class ChartFragmentTest extends AndroidTestCase { * one. The speed values of these points are 129, 130. */ public void testFillDataPoint_speed() { - // Set max speed to make the speed of points are valid. - chartFragment.setTrackMaxSpeed(200.0); - /* * At first, clear old points of speed, so give true to the second * parameter. It will not be filled in to the speed buffer. */ MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation(); - myTracksLocation1.setSpeed(129); + myTracksLocation1.setSpeed(128.5f); double[] point = fillDataPointTestHelper(myTracksLocation1); assertEquals(0.0, point[ChartView.SPEED_SERIES + 1]); @@ -285,10 +283,27 @@ public class ChartFragmentTest extends AndroidTestCase { public void testFillDataPoint_speedImperial() { // Setups to use imperial. chartFragment.setMetricUnits(false); - MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation(); - myTracksLocation.setSpeed(132); - double[] point = fillDataPointTestHelper(myTracksLocation); - assertEquals(132.0 * UnitConversions.MS_TO_KMH * UnitConversions.KM_TO_MI, + + // First data point is not added to the speed buffer + MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation(); + myTracksLocation1.setSpeed(100.0f); + double[] point = fillDataPointTestHelper(myTracksLocation1); + assertEquals(0.0, point[ChartView.SPEED_SERIES + 1]); + + MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation(); + + /* + * Add a time span here to make sure the second point is valid and the speed is valid. + * + * Speed is valid if: + * speedDifference > Constants.MAX_ACCELERATION * timeDifference + * speedDifference = 102 -100 + * timeDifference = 222 + */ + myTracksLocation2.setTime(myTracksLocation2.getTime() + 222); + myTracksLocation2.setSpeed(102); + point = fillDataPointTestHelper(myTracksLocation2); + assertEquals(102.0 * UnitConversions.MS_TO_KMH * UnitConversions.KM_TO_MI, point[ChartView.SPEED_SERIES + 1]); } @@ -298,11 +313,28 @@ public class ChartFragmentTest extends AndroidTestCase { public void testFillDataPoint_pace_nonZeroSpeed() { // Setups reportSpeed to false. chartFragment.setReportSpeed(false); - MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation(); - myTracksLocation.setSpeed(134); - double[] point = fillDataPointTestHelper(myTracksLocation); + + // First data point is not added to the speed buffer + MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation(); + myTracksLocation1.setSpeed(100.0f); + double[] point = fillDataPointTestHelper(myTracksLocation1); + assertEquals(0.0, point[ChartView.SPEED_SERIES + 1]); + + MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation(); + + /* + * Add a time span here to make sure the second point is valid and the speed is valid. + * + * Speed is valid if: + * speedDifference > Constants.MAX_ACCELERATION * timeDifference + * speedDifference = 102 -100 + * timeDifference = 222 + */ + myTracksLocation2.setTime(myTracksLocation2.getTime() + 222); + myTracksLocation2.setSpeed(102); + point = fillDataPointTestHelper(myTracksLocation2); assertEquals( - HOURS_PER_UNIT / (134.0 * UnitConversions.MS_TO_KMH), point[ChartView.PACE_SERIES + 1]); + HOURS_PER_UNIT / (102.0 * UnitConversions.MS_TO_KMH), point[ChartView.PACE_SERIES + 1]); } /**