mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 09:33:06 +02:00
Merge heads
This commit is contained in:
@@ -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.
|
||||
</string>
|
||||
<string name="gps_wait_for_signal"
|
||||
<string name="gps_wait_for_better_signal"
|
||||
translation_description="In the main view, the message on the top indicating My Tracks is
|
||||
waiting for a better GPS signal.">
|
||||
Waiting for a better GPS signal. Make sure the sky is visible.
|
||||
</string>
|
||||
|
||||
<string name="gps_wait_for_signal"
|
||||
translation_description="In the main view, the message on the top indicating My Tracks is
|
||||
waiting for a better GPS signal.">
|
||||
Waiting for GPS signal. Make sure the sky is visible.
|
||||
</string>
|
||||
|
||||
<!-- Help page -->
|
||||
<string name="help_about"
|
||||
translation_description="In the 'Help' page, the button on the bottom to open the 'About My
|
||||
|
||||
@@ -75,6 +75,7 @@ public class TrackDataHub implements DataSourceListener {
|
||||
private boolean metricUnits;
|
||||
private boolean reportSpeed;
|
||||
private int minRequiredAccuracy;
|
||||
private int minRecordingDistance;
|
||||
|
||||
// Heading values
|
||||
private float lastHeading = 0;
|
||||
@@ -347,6 +348,20 @@ public class TrackDataHub implements DataSourceListener {
|
||||
minRequiredAccuracy = PreferencesUtils.getInt(context, R.string.min_required_accuracy_key,
|
||||
PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT);
|
||||
}
|
||||
if (key == null
|
||||
|| key.equals(PreferencesUtils.getKey(context, R.string.min_recording_distance_key))) {
|
||||
minRecordingDistance = PreferencesUtils.getInt(
|
||||
context, R.string.min_recording_distance_key,
|
||||
PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT);
|
||||
if (key != null) {
|
||||
for (TrackDataListener trackDataListener :
|
||||
trackDataManager.getListeners(TrackDataType.PREFERENCE)) {
|
||||
if (trackDataListener.onMinRecordingDistanceChanged(minRecordingDistance)) {
|
||||
loadDataForListener(trackDataListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -422,6 +437,7 @@ public class TrackDataHub implements DataSourceListener {
|
||||
trackDataManager.getListeners(TrackDataType.PREFERENCE)) {
|
||||
trackDataListener.onMetricUnitsChanged(metricUnits);
|
||||
trackDataListener.onReportSpeedChanged(reportSpeed);
|
||||
trackDataListener.onMinRecordingDistanceChanged(minRecordingDistance);
|
||||
}
|
||||
|
||||
notifySelectedTrackChanged(trackDataManager.getListeners(TrackDataType.SELECTED_TRACK));
|
||||
@@ -457,6 +473,7 @@ public class TrackDataHub implements DataSourceListener {
|
||||
if (trackDataTypes.contains(TrackDataType.PREFERENCE)) {
|
||||
trackDataListener.onMetricUnitsChanged(metricUnits);
|
||||
trackDataListener.onReportSpeedChanged(reportSpeed);
|
||||
trackDataListener.onMinRecordingDistanceChanged(minRecordingDistance);
|
||||
}
|
||||
|
||||
if (trackDataTypes.contains(TrackDataType.SELECTED_TRACK)) {
|
||||
@@ -623,7 +640,7 @@ public class TrackDataHub implements DataSourceListener {
|
||||
if (!LocationUtils.isValidLocation(location)) {
|
||||
// TODO: also include the last valid point before a split
|
||||
for (TrackDataListener trackDataListener : sampledInListeners) {
|
||||
trackDataListener.onSegmentSplit();
|
||||
trackDataListener.onSegmentSplit(location);
|
||||
includeNextPoint = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -96,12 +96,13 @@ public interface TrackDataListener {
|
||||
/**
|
||||
* Called when an invalid track point representing a segment split is read.
|
||||
*/
|
||||
public void onSegmentSplit();
|
||||
public void onSegmentSplit(Location location);
|
||||
|
||||
/**
|
||||
* Called when finish sending new track points. This gets called after every
|
||||
* batch of calls to {@link #onSampledInTrackPoint(Location)},
|
||||
* {@link #onSampledOutTrackPoint(Location)} and {@link #onSegmentSplit()}.
|
||||
* {@link #onSampledOutTrackPoint(Location)} and
|
||||
* {@link #onSegmentSplit(Location)}.
|
||||
*/
|
||||
public void onNewTrackPointsDone();
|
||||
|
||||
@@ -139,4 +140,12 @@ public interface TrackDataListener {
|
||||
* @return true to reload all the data, false otherwise.
|
||||
*/
|
||||
public boolean onReportSpeedChanged(boolean reportSpeed);
|
||||
|
||||
/**
|
||||
* Called when the min recording distance preference value is changed.
|
||||
*
|
||||
* @param minRecordingDistance the new value
|
||||
* @return true to reload all the data, false otherwise.
|
||||
*/
|
||||
public boolean onMinRecordingDistanceChanged(int minRecordingDistance);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.ChartView;
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.TrackDetailActivity;
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
@@ -27,7 +26,7 @@ import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.TrackDataType;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
@@ -56,28 +55,22 @@ import java.util.EnumSet;
|
||||
public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
|
||||
public static final String CHART_FRAGMENT_TAG = "chartFragment";
|
||||
|
||||
// Android reports 128 when the speed is invalid
|
||||
private static final int INVALID_SPEED = 128;
|
||||
private final DoubleBuffer elevationBuffer = new DoubleBuffer(
|
||||
Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||
private final DoubleBuffer speedBuffer = new DoubleBuffer(Constants.SPEED_SMOOTHING_FACTOR);
|
||||
|
||||
private final ArrayList<double[]> pendingPoints = new ArrayList<double[]>();
|
||||
|
||||
|
||||
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[]. <br>
|
||||
* data[0] = time/distance <br>
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Overlay> 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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
+36
-44
@@ -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<Location> locations = new ArrayList<Location>(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<Double> distances = new Vector<Double>();
|
||||
Vector<Double> elevations = new Vector<Double>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Location> locations = new ArrayList<Location>(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<Double> distances = new Vector<Double>();
|
||||
Vector<Double> elevations = new Vector<Double>();
|
||||
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<Double> distances, Vector<Double> elevations) {
|
||||
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
|
||||
return "<p>" + track.getDescription() + "</p><p>"
|
||||
+ descriptionGenerator.generateTrackDescription(track, distances, elevations, true)
|
||||
+ "</p>";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<Double> distances, Vector<Double> elevations,
|
||||
Track track, String title, boolean metricUnits) {
|
||||
@VisibleForTesting
|
||||
static String getChartUrl(Vector<Double> distances, Vector<Double> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
+44
-12
@@ -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]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user