mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-27 19:44:45 +01:00
Merge heads
This commit is contained in:
@@ -57,7 +57,12 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
static class DatabaseHelper extends SQLiteOpenHelper {
|
static class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
public DatabaseHelper(Context context) {
|
public DatabaseHelper(Context context) {
|
||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
this(context, DATABASE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public DatabaseHelper(Context context, String databaseName) {
|
||||||
|
super(context, databaseName, null, DATABASE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -106,7 +111,8 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
*
|
*
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
private enum UrlType {
|
@VisibleForTesting
|
||||||
|
enum UrlType {
|
||||||
TRACKPOINTS, TRACKPOINTS_ID, TRACKS, TRACKS_ID, WAYPOINTS, WAYPOINTS_ID
|
TRACKPOINTS, TRACKPOINTS_ID, TRACKS, TRACKS_ID, WAYPOINTS, WAYPOINTS_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +145,8 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
* @param context context to creates database
|
* @param context context to creates database
|
||||||
* @return true means run successfully
|
* @return true means run successfully
|
||||||
*/
|
*/
|
||||||
public boolean onCreate(Context context) {
|
@VisibleForTesting
|
||||||
|
boolean onCreate(Context context) {
|
||||||
if (!canAccess()) {
|
if (!canAccess()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -457,14 +464,4 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
throw new SQLException("Failed to insert a waypoint " + url);
|
throw new SQLException("Failed to insert a waypoint " + url);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Gets the db.
|
|
||||||
*
|
|
||||||
* @return the SQLiteDatabase object
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
SQLiteDatabase getDb() {
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -306,7 +306,7 @@ public class GpxImporter extends DefaultHandler {
|
|||||||
tripStatisticsBuilder = new TripStatisticsBuilder(0);
|
tripStatisticsBuilder = new TripStatisticsBuilder(0);
|
||||||
tripStatisticsBuilder.pauseAt(0);
|
tripStatisticsBuilder.pauseAt(0);
|
||||||
}
|
}
|
||||||
track.setTripStatistics(tripStatisticsBuilder.getStatistics());
|
track.setTripStatistics(tripStatisticsBuilder.getTripStatistics());
|
||||||
track.setNumberOfPoints(numberOfLocations);
|
track.setNumberOfPoints(numberOfLocations);
|
||||||
myTracksProviderUtils.updateTrack(track);
|
myTracksProviderUtils.updateTrack(track);
|
||||||
tracksIds.add(track.getId());
|
tracksIds.add(track.getId());
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
|||||||
public void writeEndTrack(Location lastPoint) {
|
public void writeEndTrack(Location lastPoint) {
|
||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
printWriter.println("</Lap>");
|
printWriter.println("</Lap>");
|
||||||
|
printWriter.println("<Notes>" + StringUtils.formatCData(track.getDescription()) + "</Notes>");
|
||||||
printWriter.println("<Creator xsi:type=\"Device_t\">");
|
printWriter.println("<Creator xsi:type=\"Device_t\">");
|
||||||
printWriter.println("<Name>"
|
printWriter.println("<Name>"
|
||||||
+ StringUtils.formatCData(context.getString(R.string.send_google_by_my_tracks, "", ""))
|
+ StringUtils.formatCData(context.getString(R.string.send_google_by_my_tracks, "", ""))
|
||||||
|
|||||||
+2
-2
@@ -253,7 +253,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
elevationBuffer.setNext(metricUnits ? location.getAltitude()
|
elevationBuffer.setNext(metricUnits ? location.getAltitude()
|
||||||
: location.getAltitude() * UnitConversions.M_TO_FT);
|
: location.getAltitude() * UnitConversions.M_TO_FT);
|
||||||
if (i % elevationSamplingFrequency == 0) {
|
if (i % elevationSamplingFrequency == 0) {
|
||||||
distances.add(tripStatisticsBuilder.getStatistics().getTotalDistance());
|
distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance());
|
||||||
elevations.add(elevationBuffer.getAverage());
|
elevations.add(elevationBuffer.getAverage());
|
||||||
}
|
}
|
||||||
lastLocation = location;
|
lastLocation = location;
|
||||||
@@ -279,7 +279,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
|
|
||||||
// Create an end marker
|
// Create an end marker
|
||||||
if (lastLocation != null) {
|
if (lastLocation != null) {
|
||||||
distances.add(tripStatisticsBuilder.getStatistics().getTotalDistance());
|
distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance());
|
||||||
elevations.add(elevationBuffer.getAverage());
|
elevations.add(elevationBuffer.getAverage());
|
||||||
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
|
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
|
||||||
track.setDescription(
|
track.setDescription(
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
|
|||||||
elevationBuffer.setNext(metricUnits ? location.getAltitude()
|
elevationBuffer.setNext(metricUnits ? location.getAltitude()
|
||||||
: location.getAltitude() * UnitConversions.M_TO_FT);
|
: location.getAltitude() * UnitConversions.M_TO_FT);
|
||||||
if (i % elevationSamplingFrequency == 0) {
|
if (i % elevationSamplingFrequency == 0) {
|
||||||
distances.add(tripStatisticsBuilder.getStatistics().getTotalDistance());
|
distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance());
|
||||||
elevations.add(elevationBuffer.getAverage());
|
elevations.add(elevationBuffer.getAverage());
|
||||||
}
|
}
|
||||||
lastLocation = location;
|
lastLocation = location;
|
||||||
@@ -323,7 +323,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
|
|||||||
|
|
||||||
// Create an end marker
|
// Create an end marker
|
||||||
if (lastLocation != null) {
|
if (lastLocation != null) {
|
||||||
distances.add(tripStatisticsBuilder.getStatistics().getTotalDistance());
|
distances.add(tripStatisticsBuilder.getTripStatistics().getTotalDistance());
|
||||||
elevations.add(elevationBuffer.getAverage());
|
elevations.add(elevationBuffer.getAverage());
|
||||||
|
|
||||||
track.setDescription(getTrackDescription(track, distances, elevations));
|
track.setDescription(getTrackDescription(track, distances, elevations));
|
||||||
|
|||||||
+12
-19
@@ -19,41 +19,34 @@ package com.google.android.apps.mytracks.services;
|
|||||||
/**
|
/**
|
||||||
* This is a simple location listener policy that will always dictate the same
|
* This is a simple location listener policy that will always dictate the same
|
||||||
* polling interval.
|
* polling interval.
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class AbsoluteLocationListenerPolicy implements LocationListenerPolicy {
|
public class AbsoluteLocationListenerPolicy implements LocationListenerPolicy {
|
||||||
|
|
||||||
/**
|
|
||||||
* The interval to request for gps signal.
|
|
||||||
*/
|
|
||||||
private final long interval;
|
private final long interval;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param interval The interval to request for gps signal
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param interval the interval to request for gps signal
|
||||||
*/
|
*/
|
||||||
public AbsoluteLocationListenerPolicy(final long interval) {
|
public AbsoluteLocationListenerPolicy(long interval) {
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @return The interval given in the constructor
|
|
||||||
*/
|
|
||||||
public long getDesiredPollingInterval() {
|
public long getDesiredPollingInterval() {
|
||||||
return interval;
|
return interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Discards the idle time.
|
|
||||||
*/
|
|
||||||
public void updateIdleTime(long idleTime) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the minimum distance between updates.
|
|
||||||
* Get all updates to properly measure moving time.
|
|
||||||
*/
|
|
||||||
public int getMinDistance() {
|
public int getMinDistance() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateIdleTime(long idleTime) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-39
@@ -16,67 +16,58 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.services;
|
package com.google.android.apps.mytracks.services;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A LocationListenerPolicy that will change based on how long the user has been
|
* A {@link LocationListenerPolicy} that will change based on how long the user
|
||||||
* stationary.
|
* has been stationary. This policy will dictate a policy based on a min, max
|
||||||
*
|
* and idle time. The policy will dictate an interval bounded by min and max,
|
||||||
* This policy will dictate a policy based on a min, max and idle time.
|
* and is half of the idle time.
|
||||||
* The policy will dictate an interval bounded by min and max whic is half of
|
*
|
||||||
* the idle time.
|
|
||||||
*
|
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class AdaptiveLocationListenerPolicy implements LocationListenerPolicy {
|
public class AdaptiveLocationListenerPolicy implements LocationListenerPolicy {
|
||||||
|
|
||||||
/**
|
|
||||||
* Smallest interval this policy will dictate, in milliseconds.
|
|
||||||
*/
|
|
||||||
private final long minInterval;
|
private final long minInterval;
|
||||||
|
|
||||||
/**
|
|
||||||
* Largest interval this policy will dictate, in milliseconds.
|
|
||||||
*/
|
|
||||||
private final long maxInterval;
|
private final long maxInterval;
|
||||||
|
|
||||||
private final int minDistance;
|
private final int minDistance;
|
||||||
|
|
||||||
/**
|
// The time the user has been idle at the current location, in milliseconds.
|
||||||
* The time the user has been at the current location, in milliseconds.
|
|
||||||
*/
|
|
||||||
private long idleTime;
|
private long idleTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a policy that will be bounded by the given min and max.
|
* Creates a policy that will be bounded by the given minInterval and
|
||||||
*
|
* maxInterval.
|
||||||
* @param min Smallest interval this policy will dictate, in milliseconds
|
*
|
||||||
* @param max Largest interval this policy will dictate, in milliseconds
|
* @param minInterval the smallest interval this policy will dictate, in
|
||||||
|
* milliseconds
|
||||||
|
* @param maxInterval the largest interval this policy will dictate, in
|
||||||
|
* milliseconds
|
||||||
|
* @param minDistance the minimum distance in meters
|
||||||
*/
|
*/
|
||||||
public AdaptiveLocationListenerPolicy(long min, long max, int minDistance) {
|
public AdaptiveLocationListenerPolicy(long minInterval, long maxInterval, int minDistance) {
|
||||||
this.minInterval = min;
|
this.minInterval = minInterval;
|
||||||
this.maxInterval = max;
|
this.maxInterval = maxInterval;
|
||||||
this.minDistance = minDistance;
|
this.minDistance = minDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* @return An interval bounded by min and max which is half of the idle time
|
* Returns an interval half of the idle time, but bounded by minInteval and
|
||||||
|
* maxInterval.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public long getDesiredPollingInterval() {
|
public long getDesiredPollingInterval() {
|
||||||
long desiredInterval = idleTime / 2;
|
long desiredInterval = idleTime / 2;
|
||||||
// Round to avoid setting the interval too often.
|
// Round to second to avoid setting the interval too often
|
||||||
desiredInterval = (desiredInterval / 1000) * 1000;
|
desiredInterval = (desiredInterval / 1000) * 1000;
|
||||||
return Math.max(Math.min(maxInterval, desiredInterval),
|
return Math.max(Math.min(maxInterval, desiredInterval), minInterval);
|
||||||
minInterval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateIdleTime(long newIdleTime) {
|
@Override
|
||||||
this.idleTime = newIdleTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the minimum distance between updates.
|
|
||||||
*/
|
|
||||||
public int getMinDistance() {
|
public int getMinDistance() {
|
||||||
return minDistance;
|
return minDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateIdleTime(long newIdleTime) {
|
||||||
|
idleTime = newIdleTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-12
@@ -17,19 +17,18 @@
|
|||||||
package com.google.android.apps.mytracks.services;
|
package com.google.android.apps.mytracks.services;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an interface for classes that will manage the location listener policy.
|
* This is an interface for classes that will manage the location listener
|
||||||
* Different policy options are:
|
* policy. Different policy options are: {@link AbsoluteLocationListenerPolicy}
|
||||||
* Absolute
|
* and {@link AdaptiveLocationListenerPolicy}.
|
||||||
* Addaptive
|
*
|
||||||
*
|
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public interface LocationListenerPolicy {
|
public interface LocationListenerPolicy {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the polling time this policy would like at this time.
|
* Returns the polling interval this policy would like at this moment.
|
||||||
*
|
*
|
||||||
* @return The polling that this policy dictates
|
* @return the polling interval
|
||||||
*/
|
*/
|
||||||
public long getDesiredPollingInterval();
|
public long getDesiredPollingInterval();
|
||||||
|
|
||||||
@@ -39,10 +38,10 @@ public interface LocationListenerPolicy {
|
|||||||
public int getMinDistance();
|
public int getMinDistance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the amount of time the user has been idle at their current
|
* Notifies the amount of time the user has been idle at his current location.
|
||||||
* location.
|
*
|
||||||
*
|
* @param idleTime the time that the user has been idle at his current
|
||||||
* @param idleTime The time that the user has been idle at this spot
|
* location
|
||||||
*/
|
*/
|
||||||
public void updateIdleTime(long idleTime);
|
public void updateIdleTime(long idleTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.apps.mytracks.services;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that manages reading the shared preferences for the service.
|
|
||||||
*
|
|
||||||
* @author Sandor Dornbush
|
|
||||||
*/
|
|
||||||
public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
|
||||||
private TrackRecordingService service;
|
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
public PreferenceManager(TrackRecordingService service) {
|
|
||||||
this.service = service;
|
|
||||||
this.sharedPreferences = service.getSharedPreferences(
|
|
||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
|
||||||
|
|
||||||
// Refresh all properties.
|
|
||||||
onSharedPreferenceChanged(sharedPreferences, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies that preferences have changed. Call this with key == null to
|
|
||||||
* update all preferences in one call.
|
|
||||||
*
|
|
||||||
* @param key the key that changed (may be null to update all preferences)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
|
||||||
if (service == null) {
|
|
||||||
Log.w(Constants.TAG, "onSharedPreferenceChanged: a preference change (key = " + key
|
|
||||||
+ ") after a call to shutdown()");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (key == null
|
|
||||||
|| PreferencesUtils.getKey(service, R.string.recording_track_id_key).equals(key)) {
|
|
||||||
long recordingTrackId = PreferencesUtils.getLong(service, R.string.recording_track_id_key);
|
|
||||||
/*
|
|
||||||
* Only set the id if it is valid. Setting it to -1L should only happen
|
|
||||||
* in TrackRecordingService.endCurrentTrack()
|
|
||||||
*/
|
|
||||||
if (recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
|
||||||
service.setRecordingTrackId(recordingTrackId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (key == null || PreferencesUtils.getKey(service, R.string.metric_units_key).equals(key)) {
|
|
||||||
service.setMetricUnits(PreferencesUtils.getBoolean(
|
|
||||||
service, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT));
|
|
||||||
}
|
|
||||||
if (key == null
|
|
||||||
|| PreferencesUtils.getKey(service, R.string.announcement_frequency_key).equals(key)) {
|
|
||||||
service.setAnnouncementFrequency(PreferencesUtils.getInt(
|
|
||||||
service, R.string.announcement_frequency_key,
|
|
||||||
PreferencesUtils.ANNOUNCEMENT_FREQUENCY_DEFAULT));
|
|
||||||
}
|
|
||||||
if (key == null || PreferencesUtils.getKey(service, R.string.split_frequency_key).equals(key)) {
|
|
||||||
service.setSplitFrequency(PreferencesUtils.getInt(
|
|
||||||
service, R.string.split_frequency_key, PreferencesUtils.SPLIT_FREQUENCY_DEFAULT));
|
|
||||||
}
|
|
||||||
if (key == null
|
|
||||||
|| PreferencesUtils.getKey(service, R.string.min_recording_interval_key).equals(key)) {
|
|
||||||
int minRecordingInterval = PreferencesUtils.getInt(service,
|
|
||||||
R.string.min_recording_interval_key, PreferencesUtils.MIN_RECORDING_INTERVAL_DEFAULT);
|
|
||||||
switch (minRecordingInterval) {
|
|
||||||
case PreferencesUtils.MIN_RECORDING_INTERVAL_ADAPT_BATTERY_LIFE:
|
|
||||||
/*
|
|
||||||
* Choose battery life over moving time accuracy. min: 30 seconds,
|
|
||||||
* max: 5 minutes, inDist: 5 meters.
|
|
||||||
*/
|
|
||||||
service.setLocationListenerPolicy(new AdaptiveLocationListenerPolicy(30000, 300000, 5));
|
|
||||||
break;
|
|
||||||
case PreferencesUtils.MIN_RECORDING_INTERVAL_ADAPT_ACCURACY:
|
|
||||||
/*
|
|
||||||
* Get all the updates. min: 1 second, max: 30 seconds, minDist: 0
|
|
||||||
* meter.
|
|
||||||
*/
|
|
||||||
service.setLocationListenerPolicy(new AdaptiveLocationListenerPolicy(1000, 30000, 0));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
service.setLocationListenerPolicy(
|
|
||||||
new AbsoluteLocationListenerPolicy(minRecordingInterval * 1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (key == null
|
|
||||||
|| PreferencesUtils.getKey(service, R.string.min_recording_distance_key).equals(key)) {
|
|
||||||
service.setMinRecordingDistance(PreferencesUtils.getInt(
|
|
||||||
service, R.string.min_recording_distance_key,
|
|
||||||
PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT));
|
|
||||||
}
|
|
||||||
if (key == null
|
|
||||||
|| PreferencesUtils.getKey(service, R.string.max_recording_distance_key).equals(key)) {
|
|
||||||
service.setMaxRecordingDistance(PreferencesUtils.getInt(
|
|
||||||
service, R.string.max_recording_distance_key,
|
|
||||||
PreferencesUtils.MAX_RECORDING_DISTANCE_DEFAULT));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == null
|
|
||||||
|| PreferencesUtils.getKey(service, R.string.min_required_accuracy_key).equals(key)) {
|
|
||||||
service.setMinRequiredAccuracy(PreferencesUtils.getInt(
|
|
||||||
service, R.string.min_required_accuracy_key,
|
|
||||||
PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT));
|
|
||||||
}
|
|
||||||
if (key == null
|
|
||||||
|| PreferencesUtils.getKey(service, R.string.auto_resume_track_timeout_key).equals(key)) {
|
|
||||||
service.setAutoResumeTrackTimeout(PreferencesUtils.getInt(
|
|
||||||
service, R.string.auto_resume_track_timeout_key,
|
|
||||||
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() {
|
|
||||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
|
||||||
service = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+859
-954
File diff suppressed because it is too large
Load Diff
+12
-2
@@ -16,6 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks.services.tasks;
|
package com.google.android.apps.mytracks.services.tasks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
||||||
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
|
|
||||||
@@ -118,7 +119,11 @@ public class PeriodicTaskExecutor {
|
|||||||
if (!isDistanceFrequency() || periodicTask == null) {
|
if (!isDistanceFrequency() || periodicTask == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
double distance = trackRecordingService.getTripStatistics().getTotalDistance()
|
TripStatistics tripStatistics = trackRecordingService.getTripStatistics();
|
||||||
|
if (tripStatistics == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double distance = tripStatistics.getTotalDistance()
|
||||||
* UnitConversions.M_TO_KM;
|
* UnitConversions.M_TO_KM;
|
||||||
if (!metricUnits) {
|
if (!metricUnits) {
|
||||||
distance *= UnitConversions.KM_TO_MI;
|
distance *= UnitConversions.KM_TO_MI;
|
||||||
@@ -158,13 +163,18 @@ public class PeriodicTaskExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TripStatistics tripStatistics = trackRecordingService.getTripStatistics();
|
||||||
|
if (tripStatistics == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isDistanceFrequency()) {
|
if (!isDistanceFrequency()) {
|
||||||
nextTaskDistance = Double.MAX_VALUE;
|
nextTaskDistance = Double.MAX_VALUE;
|
||||||
Log.d(TAG, "SplitManager: Distance splits disabled.");
|
Log.d(TAG, "SplitManager: Distance splits disabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double distance = trackRecordingService.getTripStatistics().getTotalDistance()
|
double distance = tripStatistics.getTotalDistance()
|
||||||
* UnitConversions.M_TO_KM;
|
* UnitConversions.M_TO_KM;
|
||||||
if (!metricUnits) {
|
if (!metricUnits) {
|
||||||
distance *= UnitConversions.KM_TO_MI;
|
distance *= UnitConversions.KM_TO_MI;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.google.android.apps.mytracks.services.tasks;
|
package com.google.android.apps.mytracks.services.tasks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
||||||
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
@@ -53,6 +54,11 @@ public class TimerTaskExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TripStatistics tripStatistics = trackRecordingService.getTripStatistics();
|
||||||
|
if (tripStatistics == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
timer.purge();
|
timer.purge();
|
||||||
@@ -67,7 +73,7 @@ public class TimerTaskExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
long next = trackRecordingService.getTripStatistics().getStartTime();
|
long next = tripStatistics.getStartTime();
|
||||||
if (next < now) {
|
if (next < now) {
|
||||||
next = now + interval - ((now - next) % interval);
|
next = now + interval - ((now - next) % interval);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,66 +20,35 @@ package com.google.android.apps.mytracks.stats;
|
|||||||
* This class maintains a buffer of doubles. This buffer is a convenient class
|
* This class maintains a buffer of doubles. This buffer is a convenient class
|
||||||
* for storing a series of doubles and calculating information about them. This
|
* for storing a series of doubles and calculating information about them. This
|
||||||
* is a FIFO buffer.
|
* is a FIFO buffer.
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class DoubleBuffer {
|
public class DoubleBuffer {
|
||||||
|
|
||||||
/**
|
// The location that the next write will occur at.
|
||||||
* The location that the next write will occur at.
|
|
||||||
*/
|
|
||||||
private int index;
|
private int index;
|
||||||
|
|
||||||
/**
|
// The sliding buffer of doubles.
|
||||||
* The sliding buffer of doubles.
|
|
||||||
*/
|
|
||||||
private final double[] buffer;
|
private final double[] buffer;
|
||||||
|
|
||||||
/**
|
// True if the buffer is full
|
||||||
* Have all of the slots in the buffer been filled?
|
|
||||||
*/
|
|
||||||
private boolean isFull;
|
private boolean isFull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a buffer with size elements.
|
* Creates a buffer with a certain size.
|
||||||
*
|
*
|
||||||
* @param size the number of elements in the buffer
|
* @param size the size
|
||||||
* @throws IllegalArgumentException if the size is not a positive value
|
|
||||||
*/
|
*/
|
||||||
public DoubleBuffer(int size) {
|
public DoubleBuffer(int size) {
|
||||||
if (size < 1) {
|
if (size < 1) {
|
||||||
throw new IllegalArgumentException("The buffer size must be positive.");
|
throw new IllegalArgumentException("The buffer size must be greater than 1.");
|
||||||
}
|
}
|
||||||
buffer = new double[size];
|
buffer = new double[size];
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a double to the buffer. If the buffer is full the oldest element is
|
* Resets the buffer.
|
||||||
* overwritten.
|
|
||||||
*
|
|
||||||
* @param d the double to add
|
|
||||||
*/
|
|
||||||
public void setNext(double d) {
|
|
||||||
if (index == buffer.length) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
buffer[index] = d;
|
|
||||||
index++;
|
|
||||||
if (index == buffer.length) {
|
|
||||||
isFull = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Are all of the entries in the buffer used?
|
|
||||||
*/
|
|
||||||
public boolean isFull() {
|
|
||||||
return isFull;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the buffer to the initial state.
|
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
index = 0;
|
index = 0;
|
||||||
@@ -87,16 +56,20 @@ public class DoubleBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the average of values from the buffer.
|
* Returns true if the buffer is full.
|
||||||
*
|
*/
|
||||||
* @return The average of the buffer
|
public boolean isFull() {
|
||||||
|
return isFull;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the average of the buffer.
|
||||||
*/
|
*/
|
||||||
public double getAverage() {
|
public double getAverage() {
|
||||||
int numberOfEntries = isFull ? buffer.length : index;
|
int numberOfEntries = isFull ? buffer.length : index;
|
||||||
if (numberOfEntries == 0) {
|
if (numberOfEntries == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
for (int i = 0; i < numberOfEntries; i++) {
|
for (int i = 0; i < numberOfEntries; i++) {
|
||||||
sum += buffer[i];
|
sum += buffer[i];
|
||||||
@@ -105,15 +78,15 @@ public class DoubleBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the average and standard deviation of the buffer.
|
* Gets the average and the variance of the buffer.
|
||||||
*
|
*
|
||||||
* @return An array of two elements - the first is the average, and the second
|
* @return an array of two elements - the first is the average, the second is
|
||||||
* is the variance
|
* the variance
|
||||||
*/
|
*/
|
||||||
public double[] getAverageAndVariance() {
|
public double[] getAverageAndVariance() {
|
||||||
int numberOfEntries = isFull ? buffer.length : index;
|
int numberOfEntries = isFull ? buffer.length : index;
|
||||||
if (numberOfEntries == 0) {
|
if (numberOfEntries == 0) {
|
||||||
return new double[]{0, 0};
|
return new double[] { 0, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
@@ -124,8 +97,25 @@ public class DoubleBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double average = sum / numberOfEntries;
|
double average = sum / numberOfEntries;
|
||||||
return new double[]{average,
|
double variance = sumSquares / numberOfEntries - Math.pow(average, 2);
|
||||||
sumSquares / numberOfEntries - Math.pow(average, 2)};
|
return new double[] { average, variance };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a double to the buffer. If the buffer is full the oldest element is
|
||||||
|
* overwritten.
|
||||||
|
*
|
||||||
|
* @param value the double to add
|
||||||
|
*/
|
||||||
|
public void setNext(double value) {
|
||||||
|
if (index == buffer.length) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
buffer[index] = value;
|
||||||
|
index++;
|
||||||
|
if (index == buffer.length) {
|
||||||
|
isFull = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -20,352 +20,307 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Statistics keeper for a trip.
|
* Builder for {@link TripStatistics}. For keeping statistics as a track is
|
||||||
|
* paused/resumed and new locations are added.
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class TripStatisticsBuilder {
|
public class TripStatisticsBuilder {
|
||||||
/**
|
|
||||||
* Statistical data about the trip, which can be displayed to the user.
|
|
||||||
*/
|
|
||||||
private final TripStatistics data;
|
|
||||||
|
|
||||||
/**
|
// The trip statistics.
|
||||||
* The last location that the gps reported.
|
private final TripStatistics tripStatistics;
|
||||||
*/
|
|
||||||
private Location lastLocation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last location that contributed to the stats. It is also the last
|
|
||||||
* location the user was found to be moving.
|
|
||||||
*/
|
|
||||||
private Location lastMovingLocation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current speed in meters/second as reported by the gps.
|
|
||||||
*/
|
|
||||||
private double currentSpeed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current grade. This value is very noisy and not reported to the user.
|
|
||||||
*/
|
|
||||||
private double currentGrade;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the trip currently paused?
|
|
||||||
* All trips start paused.
|
|
||||||
*/
|
|
||||||
private boolean paused = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A buffer of the last speed readings in meters/second.
|
|
||||||
*/
|
|
||||||
private final DoubleBuffer speedBuffer =
|
|
||||||
new DoubleBuffer(Constants.SPEED_SMOOTHING_FACTOR);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A buffer of the recent elevation readings in meters.
|
|
||||||
*/
|
|
||||||
private final DoubleBuffer elevationBuffer =
|
|
||||||
new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A buffer of the distance between recent gps readings in meters.
|
|
||||||
*/
|
|
||||||
private final DoubleBuffer distanceBuffer =
|
|
||||||
new DoubleBuffer(Constants.DISTANCE_SMOOTHING_FACTOR);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A buffer of the recent grade calculations.
|
|
||||||
*/
|
|
||||||
private final DoubleBuffer gradeBuffer =
|
|
||||||
new DoubleBuffer(Constants.GRADE_SMOOTHING_FACTOR);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The total number of locations in this trip.
|
|
||||||
*/
|
|
||||||
private long totalLocations = 0;
|
|
||||||
|
|
||||||
|
// The minimum recording distance.
|
||||||
private int minRecordingDistance = PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT;
|
private int minRecordingDistance = PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT;
|
||||||
|
|
||||||
|
// True if the trip is paused. All trips start as paused.
|
||||||
|
private boolean paused = true;
|
||||||
|
|
||||||
|
// The last location as reported by GPS.
|
||||||
|
private Location lastLocation;
|
||||||
|
|
||||||
|
// The last moving location that contributed to the moving statistics.
|
||||||
|
private Location lastMovingLocation;
|
||||||
|
|
||||||
|
// A buffer of the recent speed readings (m/s) for calculating max speed.
|
||||||
|
private final DoubleBuffer speedBuffer = new DoubleBuffer(Constants.SPEED_SMOOTHING_FACTOR);
|
||||||
|
|
||||||
|
// A buffer of the recent elevation readings (m).
|
||||||
|
private final DoubleBuffer elevationBuffer = new DoubleBuffer(
|
||||||
|
Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||||
|
|
||||||
|
// A buffer of the recent distance readings for calculating grade.
|
||||||
|
private final DoubleBuffer distanceBuffer = new DoubleBuffer(Constants.DISTANCE_SMOOTHING_FACTOR);
|
||||||
|
|
||||||
|
// A buffer of the recent grade calculations
|
||||||
|
private final DoubleBuffer gradeBuffer = new DoubleBuffer(Constants.GRADE_SMOOTHING_FACTOR);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new trip starting at the given time.
|
* Creates a new trip starting at a start time.
|
||||||
*
|
*
|
||||||
* @param startTime the start time.
|
* @param startTime the start time
|
||||||
*/
|
*/
|
||||||
public TripStatisticsBuilder(long startTime) {
|
public TripStatisticsBuilder(long startTime) {
|
||||||
data = new TripStatistics();
|
tripStatistics = new TripStatistics();
|
||||||
resumeAt(startTime);
|
resumeAt(startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new trip, starting with existing statistics data.
|
* Creates a new trip, starting with an existing {@link TripStatistics}.
|
||||||
*
|
|
||||||
* @param statsData the statistics data to copy and start from
|
|
||||||
*/
|
|
||||||
public TripStatisticsBuilder(TripStatistics statsData) {
|
|
||||||
data = new TripStatistics(statsData);
|
|
||||||
if (data.getStartTime() > 0) {
|
|
||||||
resumeAt(data.getStartTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a location to the current trip. This will update all of the internal
|
|
||||||
* variables with this new location.
|
|
||||||
*
|
*
|
||||||
* @param currentLocation the current gps location
|
* @param other the existing {@link TripStatistics}
|
||||||
* @param systemTime the time used for calculation of totalTime. This should
|
|
||||||
* be the phone's time (not GPS time)
|
|
||||||
* @return true if the person is moving
|
|
||||||
*/
|
*/
|
||||||
public boolean addLocation(Location currentLocation, long systemTime) {
|
public TripStatisticsBuilder(TripStatistics other) {
|
||||||
if (paused) {
|
tripStatistics = new TripStatistics(other);
|
||||||
Log.w(TAG,
|
if (tripStatistics.getStartTime() > 0) {
|
||||||
"Tried to account for location while track is paused");
|
resumeAt(tripStatistics.getStartTime());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
totalLocations++;
|
|
||||||
|
|
||||||
double elevationDifference = updateElevation(currentLocation.getAltitude());
|
|
||||||
|
|
||||||
// Update the "instant" values:
|
|
||||||
data.setTotalTime(systemTime - data.getStartTime());
|
|
||||||
currentSpeed = currentLocation.getSpeed();
|
|
||||||
|
|
||||||
// This was the 1st location added, remember it and do nothing else:
|
|
||||||
if (lastLocation == null) {
|
|
||||||
lastLocation = currentLocation;
|
|
||||||
lastMovingLocation = currentLocation;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateBounds(currentLocation);
|
|
||||||
|
|
||||||
// Don't do anything if we didn't move since last fix:
|
|
||||||
double distance = lastLocation.distanceTo(currentLocation);
|
|
||||||
if (distance < minRecordingDistance &&
|
|
||||||
currentSpeed < Constants.MAX_NO_MOVEMENT_SPEED) {
|
|
||||||
lastLocation = currentLocation;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.addTotalDistance(lastMovingLocation.distanceTo(currentLocation));
|
|
||||||
updateSpeed(currentLocation.getTime(), currentSpeed,
|
|
||||||
lastLocation.getTime(), lastLocation.getSpeed());
|
|
||||||
|
|
||||||
updateGrade(distance, elevationDifference);
|
|
||||||
lastLocation = currentLocation;
|
|
||||||
lastMovingLocation = currentLocation;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the track's bounding box to include the given location.
|
* Sets the min recording distance.
|
||||||
*/
|
|
||||||
private void updateBounds(Location location) {
|
|
||||||
data.updateLatitudeExtremities(location.getLatitude());
|
|
||||||
data.updateLongitudeExtremities(location.getLongitude());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the elevation measurements.
|
|
||||||
*
|
*
|
||||||
* @param elevation the current elevation
|
* @param minRecordingDistance the min recording distance
|
||||||
*/
|
*/
|
||||||
// @VisibleForTesting
|
public void setMinRecordingDistance(int minRecordingDistance) {
|
||||||
double updateElevation(double elevation) {
|
this.minRecordingDistance = minRecordingDistance;
|
||||||
double oldSmoothedElevation = getSmoothedElevation();
|
|
||||||
elevationBuffer.setNext(elevation);
|
|
||||||
double smoothedElevation = getSmoothedElevation();
|
|
||||||
data.updateElevationExtremities(smoothedElevation);
|
|
||||||
double elevationDifference = elevationBuffer.isFull()
|
|
||||||
? smoothedElevation - oldSmoothedElevation
|
|
||||||
: 0.0;
|
|
||||||
if (elevationDifference > 0) {
|
|
||||||
data.addTotalElevationGain(elevationDifference);
|
|
||||||
}
|
|
||||||
return elevationDifference;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the speed measurements.
|
* Resumes the current track at a given time.
|
||||||
*
|
*
|
||||||
* @param updateTime the time of the speed update
|
* @param time the time
|
||||||
* @param speed the current speed
|
|
||||||
* @param lastLocationTime the time of the last speed update
|
|
||||||
* @param lastLocationSpeed the speed of the last update
|
|
||||||
*/
|
*/
|
||||||
// @VisibleForTesting
|
public void resumeAt(long time) {
|
||||||
void updateSpeed(long updateTime, double speed, long lastLocationTime,
|
if (!paused) {
|
||||||
double lastLocationSpeed) {
|
|
||||||
// We are now sure the user is moving.
|
|
||||||
long timeDifference = updateTime - lastLocationTime;
|
|
||||||
if (timeDifference < 0) {
|
|
||||||
Log.e(TAG,
|
|
||||||
"Found negative time change: " + timeDifference);
|
|
||||||
}
|
|
||||||
data.addMovingTime(timeDifference);
|
|
||||||
|
|
||||||
if (isValidSpeed(updateTime, speed, lastLocationTime, lastLocationSpeed,
|
|
||||||
speedBuffer)) {
|
|
||||||
speedBuffer.setNext(speed);
|
|
||||||
if (speed > data.getMaxSpeed()) {
|
|
||||||
data.setMaxSpeed(speed);
|
|
||||||
}
|
|
||||||
double movingSpeed = data.getAverageMovingSpeed();
|
|
||||||
if (speedBuffer.isFull() && (movingSpeed > data.getMaxSpeed())) {
|
|
||||||
data.setMaxSpeed(movingSpeed);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG,
|
|
||||||
"TripStatistics ignoring big change: Raw Speed: " + speed
|
|
||||||
+ " old: " + lastLocationSpeed + " [" + toString() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks to see if this is a valid speed.
|
|
||||||
*
|
|
||||||
* @param updateTime The time at the current reading
|
|
||||||
* @param speed The current speed
|
|
||||||
* @param lastLocationTime The time at the last location
|
|
||||||
* @param lastLocationSpeed Speed at the last location
|
|
||||||
* @param speedBuffer A buffer of recent readings
|
|
||||||
* @return True if this is likely a valid speed
|
|
||||||
*/
|
|
||||||
public static boolean isValidSpeed(long updateTime, double speed,
|
|
||||||
long lastLocationTime, double lastLocationSpeed,
|
|
||||||
DoubleBuffer speedBuffer) {
|
|
||||||
|
|
||||||
// We don't want to count 0 towards the speed.
|
|
||||||
if (speed == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// We are now sure the user is moving.
|
|
||||||
long timeDifference = updateTime - lastLocationTime;
|
|
||||||
|
|
||||||
// There are a lot of noisy speed readings.
|
|
||||||
// Do the cheapest checks first, most expensive last.
|
|
||||||
// The following code will ignore unlikely to be real readings.
|
|
||||||
// - 128 m/s seems to be an internal android error code.
|
|
||||||
if (Math.abs(speed - 128) < 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Another check for a spurious reading. See if the path seems physically
|
|
||||||
// likely. Ignore any speeds that imply accelaration greater than 2g's
|
|
||||||
// Really who can accelerate faster?
|
|
||||||
double speedDifference = Math.abs(lastLocationSpeed - speed);
|
|
||||||
if (speedDifference > Constants.MAX_ACCELERATION * timeDifference) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are three additional checks if the reading gets this far:
|
|
||||||
// - Only use the speed if the buffer is full
|
|
||||||
// - Check that the current speed is less than 10x the recent smoothed speed
|
|
||||||
// - Double check that the current speed does not imply crazy acceleration
|
|
||||||
double smoothedSpeed = speedBuffer.getAverage();
|
|
||||||
double smoothedDiff = Math.abs(smoothedSpeed - speed);
|
|
||||||
return !speedBuffer.isFull() ||
|
|
||||||
(speed < smoothedSpeed * 10
|
|
||||||
&& smoothedDiff < Constants.MAX_ACCELERATION * timeDifference);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the grade measurements.
|
|
||||||
*
|
|
||||||
* @param distance the distance the user just traveled
|
|
||||||
* @param elevationDifference the elevation difference between the current
|
|
||||||
* reading and the previous reading
|
|
||||||
*/
|
|
||||||
// @VisibleForTesting
|
|
||||||
void updateGrade(double distance, double elevationDifference) {
|
|
||||||
distanceBuffer.setNext(distance);
|
|
||||||
double smoothedDistance = distanceBuffer.getAverage();
|
|
||||||
|
|
||||||
// With the error in the altitude measurement it is dangerous to divide
|
|
||||||
// by anything less than 5.
|
|
||||||
if (!elevationBuffer.isFull() || !distanceBuffer.isFull()
|
|
||||||
|| smoothedDistance < 5.0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentGrade = elevationDifference / smoothedDistance;
|
|
||||||
gradeBuffer.setNext(currentGrade);
|
tripStatistics.setStartTime(time);
|
||||||
data.updateGradeExtremities(gradeBuffer.getAverage());
|
tripStatistics.setStopTime(-1L);
|
||||||
|
paused = false;
|
||||||
|
lastLocation = null;
|
||||||
|
lastMovingLocation = null;
|
||||||
|
speedBuffer.reset();
|
||||||
|
elevationBuffer.reset();
|
||||||
|
distanceBuffer.reset();
|
||||||
|
gradeBuffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses the track at the given time.
|
* Pauses the track at a given time.
|
||||||
*
|
*
|
||||||
* @param time the time to pause at
|
* @param time the time to pause at
|
||||||
*/
|
*/
|
||||||
public void pauseAt(long time) {
|
public void pauseAt(long time) {
|
||||||
if (paused) { return; }
|
if (paused) {
|
||||||
|
return;
|
||||||
data.setStopTime(time);
|
}
|
||||||
data.setTotalTime(time - data.getStartTime());
|
tripStatistics.setStopTime(time);
|
||||||
lastLocation = null; // Make sure the counter restarts.
|
// TODO: total time needs to take into account pauses
|
||||||
|
tripStatistics.setTotalTime(time - tripStatistics.getStartTime());
|
||||||
paused = true;
|
paused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resumes the current track at the given time.
|
* Gets the trip statistics.
|
||||||
*
|
|
||||||
* @param time the time to resume at
|
|
||||||
*/
|
*/
|
||||||
public void resumeAt(long time) {
|
public TripStatistics getTripStatistics() {
|
||||||
if (!paused) { return; }
|
// Take a snapshot - we don't want anyone messing with our internals
|
||||||
|
return new TripStatistics(tripStatistics);
|
||||||
// TODO: The times are bogus if the track is paused then resumed again
|
|
||||||
data.setStartTime(time);
|
|
||||||
data.setStopTime(-1);
|
|
||||||
paused = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "TripStatistics { Data: " + data.toString()
|
|
||||||
+ "; Total Locations: " + totalLocations
|
|
||||||
+ "; Paused: " + paused
|
|
||||||
+ "; Current speed: " + currentSpeed
|
|
||||||
+ "; Current grade: " + currentGrade
|
|
||||||
+ "}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the amount of time the user has been idle or 0 if they are moving.
|
* Returns the amount of time the user has been idle or 0 if he is moving.
|
||||||
*/
|
*/
|
||||||
public long getIdleTime() {
|
public long getIdleTime() {
|
||||||
if (lastLocation == null || lastMovingLocation == null)
|
if (lastLocation == null || lastMovingLocation == null) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
return lastLocation.getTime() - lastMovingLocation.getTime();
|
return lastLocation.getTime() - lastMovingLocation.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current elevation smoothed over several readings. The elevation
|
* Gets the smoothed elevation over several readings. The elevation readings
|
||||||
* data is very noisy so it is better to use the smoothed elevation than the
|
* is noisy so the smoothed elevation is better than the raw elevation for
|
||||||
* raw elevation for many tasks.
|
* many tasks.
|
||||||
*
|
|
||||||
* @return The elevation smoothed over several readings
|
|
||||||
*/
|
*/
|
||||||
public double getSmoothedElevation() {
|
public double getSmoothedElevation() {
|
||||||
return elevationBuffer.getAverage();
|
return elevationBuffer.getAverage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TripStatistics getStatistics() {
|
/**
|
||||||
// Take a snapshot - we don't want anyone messing with our internals
|
* Adds a location. This will update all of the internal variables with this
|
||||||
return new TripStatistics(data);
|
* new location.
|
||||||
|
*
|
||||||
|
* @param location the location
|
||||||
|
* @param systemTime the system time for calculating totalTime. This should be
|
||||||
|
* the phone's system time (not GPS time)
|
||||||
|
* @return true if the person is moving
|
||||||
|
*/
|
||||||
|
public boolean addLocation(Location location, long systemTime) {
|
||||||
|
if (paused) {
|
||||||
|
Log.w(TAG, "Track is paused. Ignore addLocation.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tripStatistics.setTotalTime(systemTime - tripStatistics.getStartTime());
|
||||||
|
|
||||||
|
double elevationDifference = updateElevation(location.getAltitude());
|
||||||
|
tripStatistics.updateLatitudeExtremities(location.getLatitude());
|
||||||
|
tripStatistics.updateLongitudeExtremities(location.getLongitude());
|
||||||
|
|
||||||
|
// If this is the first location, remember it and return.
|
||||||
|
if (lastLocation == null || lastMovingLocation == null) {
|
||||||
|
lastLocation = location;
|
||||||
|
lastMovingLocation = location;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't do anything more if we didn't move since the last location.
|
||||||
|
double distance = lastLocation.distanceTo(location);
|
||||||
|
if (distance < minRecordingDistance && location.getSpeed() < Constants.MAX_NO_MOVEMENT_SPEED) {
|
||||||
|
lastLocation = location;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long timeDifference = location.getTime() - lastLocation.getTime();
|
||||||
|
if (timeDifference < 0) {
|
||||||
|
Log.e(TAG, "Negative time difference: " + timeDifference);
|
||||||
|
lastLocation = location;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tripStatistics.addTotalDistance(lastMovingLocation.distanceTo(location));
|
||||||
|
tripStatistics.addMovingTime(timeDifference);
|
||||||
|
updateSpeed(
|
||||||
|
location.getTime(), location.getSpeed(), lastLocation.getTime(), lastLocation.getSpeed());
|
||||||
|
updateGrade(distance, elevationDifference);
|
||||||
|
lastLocation = location;
|
||||||
|
lastMovingLocation = location;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMinRecordingDistance(int minRecordingDistance) {
|
/**
|
||||||
this.minRecordingDistance = minRecordingDistance;
|
* Updates a speed reading. Assumes the user is moving.
|
||||||
|
*
|
||||||
|
* @param time the time
|
||||||
|
* @param speed the speed
|
||||||
|
* @param lastLocationTime the last location time
|
||||||
|
* @param lastLocationSpeed the last location speed
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
void updateSpeed(long time, double speed, long lastLocationTime, double lastLocationSpeed) {
|
||||||
|
if (!isValidSpeed(time, speed, lastLocationTime, lastLocationSpeed, speedBuffer)) {
|
||||||
|
Log.d(TAG, "Invalid speed. speed: " + speed + " lastLocationSpeed: " + lastLocationSpeed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
speedBuffer.setNext(speed);
|
||||||
|
if (speed > tripStatistics.getMaxSpeed()) {
|
||||||
|
tripStatistics.setMaxSpeed(speed);
|
||||||
|
}
|
||||||
|
double movingSpeed = tripStatistics.getAverageMovingSpeed();
|
||||||
|
if (speedBuffer.isFull() && movingSpeed > tripStatistics.getMaxSpeed()) {
|
||||||
|
tripStatistics.setMaxSpeed(movingSpeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an elevation reading.
|
||||||
|
*
|
||||||
|
* @param elevation the elevation
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
double updateElevation(double elevation) {
|
||||||
|
double oldAverage = elevationBuffer.getAverage();
|
||||||
|
elevationBuffer.setNext(elevation);
|
||||||
|
double newAverage = elevationBuffer.getAverage();
|
||||||
|
tripStatistics.updateElevationExtremities(newAverage);
|
||||||
|
double elevationDifference = elevationBuffer.isFull() ? newAverage - oldAverage : 0.0;
|
||||||
|
if (elevationDifference > 0) {
|
||||||
|
tripStatistics.addTotalElevationGain(elevationDifference);
|
||||||
|
}
|
||||||
|
return elevationDifference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a grade reading.
|
||||||
|
*
|
||||||
|
* @param distance the distance the user just traveled
|
||||||
|
* @param elevationDifference the elevation difference between the current
|
||||||
|
* reading and the previous reading
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
void updateGrade(double distance, double elevationDifference) {
|
||||||
|
distanceBuffer.setNext(distance);
|
||||||
|
double smoothedDistance = distanceBuffer.getAverage();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With the error in the altitude measurement it is dangerous to divide by
|
||||||
|
* anything less than 5.
|
||||||
|
*/
|
||||||
|
if (!elevationBuffer.isFull() || !distanceBuffer.isFull() || smoothedDistance < 5.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gradeBuffer.setNext(elevationDifference / smoothedDistance);
|
||||||
|
tripStatistics.updateGradeExtremities(gradeBuffer.getAverage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the speed is valid.
|
||||||
|
*
|
||||||
|
* @param time the time
|
||||||
|
* @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) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are a lot of noisy speed readings. Do the cheapest checks first,
|
||||||
|
* most expensive last.
|
||||||
|
*/
|
||||||
|
if (speed == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following code will ignore unlikely readings. 128 m/s seems to be an
|
||||||
|
* internal android error code.
|
||||||
|
*/
|
||||||
|
if (Math.abs(speed - 128) < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if the speed seems physically likely. Ignore any speeds that imply
|
||||||
|
* acceleration greater than 2g.
|
||||||
|
*/
|
||||||
|
long timeDifference = time - lastLocationTime;
|
||||||
|
double speedDifference = Math.abs(lastLocationSpeed - speed);
|
||||||
|
if (speedDifference > Constants.MAX_ACCELERATION * timeDifference) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only check if the speed buffer is full. Check that the speed is less than
|
||||||
|
* 10X the smoothed average and the speed difference doesn't imply 2g
|
||||||
|
* acceleration.
|
||||||
|
*/
|
||||||
|
if (!speedBuffer.isFull()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
double average = speedBuffer.getAverage();
|
||||||
|
double diff = Math.abs(average - speed);
|
||||||
|
return (speed < average * 10) && (diff < Constants.MAX_ACCELERATION * timeDifference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,13 @@ public interface MyTracksProviderUtils {
|
|||||||
*/
|
*/
|
||||||
public long getLastWaypointId(long trackId);
|
public long getLastWaypointId(long trackId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the last statistics waypoint for a track. Returns null if it doesn't exist.
|
||||||
|
*
|
||||||
|
* @param trackId the track id
|
||||||
|
*/
|
||||||
|
public Waypoint getLastStatisticsWaypoint(long trackId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the next marker number. Returns -1 if not able to get the next marker
|
* Gets the next marker number. Returns -1 if not able to get the next marker
|
||||||
* number.
|
* number.
|
||||||
|
|||||||
+23
@@ -443,6 +443,29 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
|||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Waypoint getLastStatisticsWaypoint(long trackId) {
|
||||||
|
if (trackId < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
String selection = WaypointsColumns.TRACKID + "=? AND " + WaypointsColumns.TYPE + "="
|
||||||
|
+ Waypoint.TYPE_STATISTICS;
|
||||||
|
String[] selectionArgs = new String[] { Long.toString(trackId) };
|
||||||
|
cursor = getWaypointsCursor(
|
||||||
|
null, selection, selectionArgs, WaypointsColumns._ID + " DESC", 1);
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
return createWaypoint(cursor);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNextMarkerNumber(long trackId, boolean statistics) {
|
public int getNextMarkerNumber(long trackId, boolean statistics) {
|
||||||
if (trackId < 0) {
|
if (trackId < 0) {
|
||||||
|
|||||||
@@ -18,19 +18,15 @@ package com.google.android.apps.mytracks.stats;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class that tracks a minimum and a maximum of a variable.
|
* A helper class that tracks a minimum and a maximum of a variable.
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class ExtremityMonitor {
|
public class ExtremityMonitor {
|
||||||
|
|
||||||
/**
|
// The smallest value seen so far.
|
||||||
* The smallest value seen so far.
|
|
||||||
*/
|
|
||||||
private double min;
|
private double min;
|
||||||
|
|
||||||
/**
|
// The largest value seen so far.
|
||||||
* The largest value seen so far.
|
|
||||||
*/
|
|
||||||
private double max;
|
private double max;
|
||||||
|
|
||||||
public ExtremityMonitor() {
|
public ExtremityMonitor() {
|
||||||
@@ -38,9 +34,31 @@ public class ExtremityMonitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the min and the max with the new value.
|
* Resets this object to it's initial state where the min and max are unknown.
|
||||||
*
|
*/
|
||||||
* @param value the new value for the monitor
|
public void reset() {
|
||||||
|
min = Double.POSITIVE_INFINITY;
|
||||||
|
max = Double.NEGATIVE_INFINITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum value seen.
|
||||||
|
*/
|
||||||
|
public double getMin() {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum value seen.
|
||||||
|
*/
|
||||||
|
public double getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the min and the max with a new value.
|
||||||
|
*
|
||||||
|
* @param value the new value
|
||||||
* @return true if an extremity was found
|
* @return true if an extremity was found
|
||||||
*/
|
*/
|
||||||
public boolean update(double value) {
|
public boolean update(double value) {
|
||||||
@@ -56,34 +74,11 @@ public class ExtremityMonitor {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the minimum value seen.
|
|
||||||
*
|
|
||||||
* @return The minimum value passed into the update() function
|
|
||||||
*/
|
|
||||||
public double getMin() {
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the maximum value seen.
|
|
||||||
*
|
|
||||||
* @return The maximum value passed into the update() function
|
|
||||||
*/
|
|
||||||
public double getMax() {
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets this object to it's initial state where the min and max are unknown.
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
min = Double.POSITIVE_INFINITY;
|
|
||||||
max = Double.NEGATIVE_INFINITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the minimum and maximum values.
|
* Sets the minimum and maximum values.
|
||||||
|
*
|
||||||
|
* @param min the minimum value
|
||||||
|
* @param max the maximum value
|
||||||
*/
|
*/
|
||||||
public void set(double min, double max) {
|
public void set(double min, double max) {
|
||||||
this.min = min;
|
this.min = min;
|
||||||
@@ -92,6 +87,8 @@ public class ExtremityMonitor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the minimum value.
|
* Sets the minimum value.
|
||||||
|
*
|
||||||
|
* @param min the minimum value
|
||||||
*/
|
*/
|
||||||
public void setMin(double min) {
|
public void setMin(double min) {
|
||||||
this.min = min;
|
this.min = min;
|
||||||
@@ -99,16 +96,20 @@ public class ExtremityMonitor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the maximum value.
|
* Sets the maximum value.
|
||||||
|
*
|
||||||
|
* @param max the maximum value
|
||||||
*/
|
*/
|
||||||
public void setMax(double max) {
|
public void setMax(double max) {
|
||||||
this.max = max;
|
this.max = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if has data.
|
||||||
|
*/
|
||||||
public boolean hasData() {
|
public boolean hasData() {
|
||||||
return min != Double.POSITIVE_INFINITY
|
return min != Double.POSITIVE_INFINITY && max != Double.NEGATIVE_INFINITY;
|
||||||
&& max != Double.NEGATIVE_INFINITY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Min: " + min + " Max: " + max;
|
return "Min: " + min + " Max: " + max;
|
||||||
|
|||||||
@@ -13,182 +13,226 @@
|
|||||||
* License for the specific language governing permissions and limitations under
|
* License for the specific language governing permissions and limitations under
|
||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.android.apps.mytracks.stats;
|
package com.google.android.apps.mytracks.stats;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Statistical data about a trip.
|
* Statistical data about a trip. The data in this class should be filled out by
|
||||||
* The data in this class should be filled out by TripStatisticsBuilder.
|
* TripStatisticsBuilder.
|
||||||
*
|
* <p>
|
||||||
* TODO: hashCode and equals
|
* TODO: hashCode and equals
|
||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class TripStatistics implements Parcelable {
|
public class TripStatistics implements Parcelable {
|
||||||
|
|
||||||
/**
|
// The trip start time. This is the system time, might not match the GPs time.
|
||||||
* The start time for the trip. This is system time which might not match gps
|
|
||||||
* time.
|
|
||||||
*/
|
|
||||||
private long startTime = -1L;
|
private long startTime = -1L;
|
||||||
|
|
||||||
/**
|
// The trip stop time. This is the system time, might not match the GPS time.
|
||||||
* The stop time for the trip. This is the system time which might not match
|
|
||||||
* gps time.
|
|
||||||
*/
|
|
||||||
private long stopTime = -1L;
|
private long stopTime = -1L;
|
||||||
|
|
||||||
/**
|
// The total trip distance (meters).
|
||||||
* The total time that we believe the user was traveling in milliseconds.
|
|
||||||
*/
|
|
||||||
private long movingTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The total time of the trip in milliseconds.
|
|
||||||
* This is only updated when new points are received, so it may be stale.
|
|
||||||
*/
|
|
||||||
private long totalTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The total distance in meters that the user traveled on this trip.
|
|
||||||
*/
|
|
||||||
private double totalDistance;
|
private double totalDistance;
|
||||||
|
|
||||||
/**
|
// The total time (ms). Updated when new points are received, may be stale.
|
||||||
* The total elevation gained on this trip in meters.
|
private long totalTime;
|
||||||
*/
|
|
||||||
private double totalElevationGain;
|
|
||||||
|
|
||||||
/**
|
// The total moving time (ms). Based on when we believe the user is traveling.
|
||||||
* The maximum speed in meters/second reported that we believe to be a valid
|
private long movingTime;
|
||||||
* speed.
|
|
||||||
*/
|
|
||||||
private double maxSpeed;
|
|
||||||
|
|
||||||
/**
|
// The min and max latitude seen in this trip.
|
||||||
* The min and max latitude values seen in this trip.
|
|
||||||
*/
|
|
||||||
private final ExtremityMonitor latitudeExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor latitudeExtremities = new ExtremityMonitor();
|
||||||
|
|
||||||
/**
|
// The min and max longitude seen in this trip.
|
||||||
* The min and max longitude values seen in this trip.
|
|
||||||
*/
|
|
||||||
private final ExtremityMonitor longitudeExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor longitudeExtremities = new ExtremityMonitor();
|
||||||
|
|
||||||
/**
|
// The maximum speed (meters/second) that we believe is valid.
|
||||||
* The min and max elevation seen on this trip in meters.
|
private double maxSpeed;
|
||||||
*/
|
|
||||||
|
// The min and max elevation (meters) seen on this trip.
|
||||||
private final ExtremityMonitor elevationExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor elevationExtremities = new ExtremityMonitor();
|
||||||
|
|
||||||
/**
|
// The total elevation gained (meters).
|
||||||
* The minimum and maximum grade calculations on this trip.
|
private double totalElevationGain;
|
||||||
*/
|
|
||||||
|
// The min and max grade seen on this trip.
|
||||||
private final ExtremityMonitor gradeExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor gradeExtremities = new ExtremityMonitor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
public TripStatistics() {
|
public TripStatistics() {}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor.
|
* Copy constructor.
|
||||||
*
|
*
|
||||||
* @param other another statistics data object to copy from
|
* @param other another statistics data object to copy from
|
||||||
*/
|
*/
|
||||||
public TripStatistics(TripStatistics other) {
|
public TripStatistics(TripStatistics other) {
|
||||||
this.maxSpeed = other.maxSpeed;
|
|
||||||
this.movingTime = other.movingTime;
|
|
||||||
this.startTime = other.startTime;
|
this.startTime = other.startTime;
|
||||||
this.stopTime = other.stopTime;
|
this.stopTime = other.stopTime;
|
||||||
this.totalDistance = other.totalDistance;
|
this.totalDistance = other.totalDistance;
|
||||||
this.totalElevationGain = other.totalElevationGain;
|
|
||||||
this.totalTime = other.totalTime;
|
this.totalTime = other.totalTime;
|
||||||
|
this.movingTime = other.movingTime;
|
||||||
this.latitudeExtremities.set(other.latitudeExtremities.getMin(),
|
this.latitudeExtremities.set(
|
||||||
other.latitudeExtremities.getMax());
|
other.latitudeExtremities.getMin(), other.latitudeExtremities.getMax());
|
||||||
this.longitudeExtremities.set(other.longitudeExtremities.getMin(),
|
this.longitudeExtremities.set(
|
||||||
other.longitudeExtremities.getMax());
|
other.longitudeExtremities.getMin(), other.longitudeExtremities.getMax());
|
||||||
this.elevationExtremities.set(other.elevationExtremities.getMin(),
|
this.maxSpeed = other.maxSpeed;
|
||||||
other.elevationExtremities.getMax());
|
this.elevationExtremities.set(
|
||||||
this.gradeExtremities.set(other.gradeExtremities.getMin(),
|
other.elevationExtremities.getMin(), other.elevationExtremities.getMax());
|
||||||
other.gradeExtremities.getMax());
|
this.totalElevationGain = other.totalElevationGain;
|
||||||
|
this.gradeExtremities.set(other.gradeExtremities.getMin(), other.gradeExtremities.getMax());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combines these statistics with those from another object.
|
* Combines these statistics with those from another object. This assumes that
|
||||||
* This assumes that the time periods covered by each do not intersect.
|
* the time periods covered by each do not intersect.
|
||||||
*
|
*
|
||||||
* @param other the other waypoint
|
* @param other another statistics data object
|
||||||
*/
|
*/
|
||||||
public void merge(TripStatistics other) {
|
public void merge(TripStatistics other) {
|
||||||
startTime = Math.min(startTime, other.startTime);
|
startTime = Math.min(startTime, other.startTime);
|
||||||
stopTime = Math.max(stopTime, other.stopTime);
|
stopTime = Math.max(stopTime, other.stopTime);
|
||||||
|
totalDistance += other.totalDistance;
|
||||||
totalTime += other.totalTime;
|
totalTime += other.totalTime;
|
||||||
movingTime += other.movingTime;
|
movingTime += other.movingTime;
|
||||||
totalDistance += other.totalDistance;
|
|
||||||
totalElevationGain += other.totalElevationGain;
|
|
||||||
maxSpeed = Math.max(maxSpeed, other.maxSpeed);
|
|
||||||
|
|
||||||
latitudeExtremities.update(other.latitudeExtremities.getMax());
|
|
||||||
latitudeExtremities.update(other.latitudeExtremities.getMin());
|
latitudeExtremities.update(other.latitudeExtremities.getMin());
|
||||||
longitudeExtremities.update(other.longitudeExtremities.getMax());
|
latitudeExtremities.update(other.latitudeExtremities.getMax());
|
||||||
longitudeExtremities.update(other.longitudeExtremities.getMin());
|
longitudeExtremities.update(other.longitudeExtremities.getMin());
|
||||||
elevationExtremities.update(other.elevationExtremities.getMax());
|
longitudeExtremities.update(other.longitudeExtremities.getMax());
|
||||||
|
maxSpeed = Math.max(maxSpeed, other.maxSpeed);
|
||||||
elevationExtremities.update(other.elevationExtremities.getMin());
|
elevationExtremities.update(other.elevationExtremities.getMin());
|
||||||
gradeExtremities.update(other.gradeExtremities.getMax());
|
elevationExtremities.update(other.elevationExtremities.getMax());
|
||||||
|
totalElevationGain += other.totalElevationGain;
|
||||||
gradeExtremities.update(other.gradeExtremities.getMin());
|
gradeExtremities.update(other.gradeExtremities.getMin());
|
||||||
|
gradeExtremities.update(other.gradeExtremities.getMax());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the time that this track started.
|
* Gets the trip start time. The number of milliseconds since epoch.
|
||||||
*
|
|
||||||
* @return The number of milliseconds since epoch to the time when this track
|
|
||||||
* started
|
|
||||||
*/
|
*/
|
||||||
public long getStartTime() {
|
public long getStartTime() {
|
||||||
return startTime;
|
return startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the time that this track stopped.
|
* Gets the trip stop time. The number of milliseconds since epoch.
|
||||||
*
|
|
||||||
* @return The number of milliseconds since epoch to the time when this track
|
|
||||||
* stopped
|
|
||||||
*/
|
*/
|
||||||
public long getStopTime() {
|
public long getStopTime() {
|
||||||
return stopTime;
|
return stopTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the total time that this track has been active.
|
* Gets the total distance the user traveled in meters.
|
||||||
* This statistic is only updated when a new point is added to the statistics,
|
|
||||||
* so it may be off. If you need to calculate the proper total time, use
|
|
||||||
* {@link #getStartTime} with the current time.
|
|
||||||
*
|
|
||||||
* @return The total number of milliseconds the track was active
|
|
||||||
*/
|
|
||||||
public long getTotalTime() {
|
|
||||||
return totalTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the total distance the user traveled.
|
|
||||||
*
|
|
||||||
* @return The total distance traveled in meters
|
|
||||||
*/
|
*/
|
||||||
public double getTotalDistance() {
|
public double getTotalDistance() {
|
||||||
return totalDistance;
|
return totalDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the the average speed the user traveled.
|
* Gets the total time in milliseconds that this track has been active. This
|
||||||
* This calculation only takes into account the displacement until the last
|
* statistic is only updated when a new point is added to the statistics, so
|
||||||
* point that was accounted for in statistics.
|
* it may be off. If you need to calculate the proper total time, use
|
||||||
*
|
* {@link #getStartTime} with the current time.
|
||||||
* @return The average speed in m/s
|
*/
|
||||||
|
public long getTotalTime() {
|
||||||
|
return totalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the moving time in milliseconds.
|
||||||
|
*/
|
||||||
|
public long getMovingTime() {
|
||||||
|
return movingTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the topmost position (highest latitude) of the track, in signed
|
||||||
|
* degrees.
|
||||||
|
*/
|
||||||
|
public double getTopDegrees() {
|
||||||
|
return latitudeExtremities.getMax();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the topmost position (highest latitude) of the track, in signed
|
||||||
|
* millions of degrees.
|
||||||
|
*/
|
||||||
|
public int getTop() {
|
||||||
|
return (int) (latitudeExtremities.getMax() * 1E6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bottommost position (lowest latitude) of the track, in signed
|
||||||
|
* degrees.
|
||||||
|
*/
|
||||||
|
public double getBottomDegrees() {
|
||||||
|
return latitudeExtremities.getMin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bottommost position (lowest latitude) of the track, in signed
|
||||||
|
* millions of degrees.
|
||||||
|
*/
|
||||||
|
public int getBottom() {
|
||||||
|
return (int) (latitudeExtremities.getMin() * 1E6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the leftmost position (lowest longitude) of the track, in signed
|
||||||
|
* degrees.
|
||||||
|
*/
|
||||||
|
public double getLeftDegrees() {
|
||||||
|
return longitudeExtremities.getMin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the leftmost position (lowest longitude) of the track, in signed
|
||||||
|
* millions of degrees.
|
||||||
|
*/
|
||||||
|
public int getLeft() {
|
||||||
|
return (int) (longitudeExtremities.getMin() * 1E6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the rightmost position (highest longitude) of the track, in signed
|
||||||
|
* degrees.
|
||||||
|
*/
|
||||||
|
public double getRightDegrees() {
|
||||||
|
return longitudeExtremities.getMax();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the rightmost position (highest longitude) of the track, in signed
|
||||||
|
* millions of degrees.
|
||||||
|
*/
|
||||||
|
public int getRight() {
|
||||||
|
return (int) (longitudeExtremities.getMax() * 1E6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the mean latitude position of the track, in signed degrees.
|
||||||
|
*/
|
||||||
|
public double getMeanLatitude() {
|
||||||
|
return (getBottomDegrees() + getTopDegrees()) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the mean longitude position of the track, in signed degrees.
|
||||||
|
*/
|
||||||
|
public double getMeanLongitude() {
|
||||||
|
return (getLeftDegrees() + getRightDegrees()) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the average speed in meters/second. This calculation only takes into
|
||||||
|
* account the displacement until the last point that was accounted for in
|
||||||
|
* statistics.
|
||||||
*/
|
*/
|
||||||
public double getAverageSpeed() {
|
public double getAverageSpeed() {
|
||||||
if (totalTime == 0L) {
|
if (totalTime == 0L) {
|
||||||
@@ -198,10 +242,7 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the the average speed the user traveled when they were actively
|
* Gets the average moving speed in meters/second.
|
||||||
* moving.
|
|
||||||
*
|
|
||||||
* @return The average moving speed in m/s
|
|
||||||
*/
|
*/
|
||||||
public double getAverageMovingSpeed() {
|
public double getAverageMovingSpeed() {
|
||||||
if (movingTime == 0L) {
|
if (movingTime == 0L) {
|
||||||
@@ -211,261 +252,80 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the the maximum speed for this track.
|
* Gets the maximum speed in meters/second.
|
||||||
*
|
|
||||||
* @return The maximum speed in m/s
|
|
||||||
*/
|
*/
|
||||||
public double getMaxSpeed() {
|
public double getMaxSpeed() {
|
||||||
return maxSpeed;
|
return maxSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the moving time.
|
* Gets the minimum elevation. This is calculated from the smoothed elevation
|
||||||
*
|
* so this can actually be more than the current elevation.
|
||||||
* @return The total number of milliseconds the user was moving
|
|
||||||
*/
|
|
||||||
public long getMovingTime() {
|
|
||||||
return movingTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the total elevation gain for this trip. This is calculated as the sum
|
|
||||||
* of all positive differences in the smoothed elevation.
|
|
||||||
*
|
|
||||||
* @return The elevation gain in meters for this trip
|
|
||||||
*/
|
|
||||||
public double getTotalElevationGain() {
|
|
||||||
return totalElevationGain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the leftmost position (lowest longitude) of the track, in signed degrees.
|
|
||||||
*/
|
|
||||||
public double getLeftDegrees() {
|
|
||||||
return longitudeExtremities.getMin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the leftmost position (lowest longitude) of the track, in signed millions of degrees.
|
|
||||||
*/
|
|
||||||
public int getLeft() {
|
|
||||||
return (int) (longitudeExtremities.getMin() * 1E6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the rightmost position (highest longitude) of the track, in signed degrees.
|
|
||||||
*/
|
|
||||||
public double getRightDegrees() {
|
|
||||||
return longitudeExtremities.getMax();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the rightmost position (highest longitude) of the track, in signed millions of degrees.
|
|
||||||
*/
|
|
||||||
public int getRight() {
|
|
||||||
return (int) (longitudeExtremities.getMax() * 1E6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the bottommost position (lowest latitude) of the track, in signed degrees.
|
|
||||||
*/
|
|
||||||
public double getBottomDegrees() {
|
|
||||||
return latitudeExtremities.getMin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the bottommost position (lowest latitude) of the track, in signed millions of degrees.
|
|
||||||
*/
|
|
||||||
public int getBottom() {
|
|
||||||
return (int) (latitudeExtremities.getMin() * 1E6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the topmost position (highest latitude) of the track, in signed degrees.
|
|
||||||
*/
|
|
||||||
public double getTopDegrees() {
|
|
||||||
return latitudeExtremities.getMax();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the topmost position (highest latitude) of the track, in signed millions of degrees.
|
|
||||||
*/
|
|
||||||
public int getTop() {
|
|
||||||
return (int) (latitudeExtremities.getMax() * 1E6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the mean position (center latitude) of the track, in signed degrees.
|
|
||||||
*/
|
|
||||||
public double getMeanLatitude() {
|
|
||||||
return (getBottomDegrees() + getTopDegrees()) / 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the mean position (center longitude) of the track, in signed degrees.
|
|
||||||
*/
|
|
||||||
public double getMeanLongitude() {
|
|
||||||
return (getLeftDegrees() + getRightDegrees()) / 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the minimum elevation seen on this trip. This is calculated from the
|
|
||||||
* smoothed elevation so this can actually be more than the current elevation.
|
|
||||||
*
|
|
||||||
* @return The smallest elevation reading for this trip in meters
|
|
||||||
*/
|
*/
|
||||||
public double getMinElevation() {
|
public double getMinElevation() {
|
||||||
return elevationExtremities.getMin();
|
return elevationExtremities.getMin();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum elevation seen on this trip. This is calculated from the
|
* Gets the maximum elevation. This is calculated from the smoothed elevation
|
||||||
* smoothed elevation so this can actually be less than the current elevation.
|
* so this can actually be less than the current elevation.
|
||||||
*
|
|
||||||
* @return The largest elevation reading for this trip in meters
|
|
||||||
*/
|
*/
|
||||||
public double getMaxElevation() {
|
public double getMaxElevation() {
|
||||||
return elevationExtremities.getMax();
|
return elevationExtremities.getMax();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total elevation gain in meters. This is calculated as the sum of
|
||||||
|
* all positive differences in the smoothed elevation.
|
||||||
|
*/
|
||||||
|
public double getTotalElevationGain() {
|
||||||
|
return totalElevationGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum grade for this trip.
|
||||||
|
*/
|
||||||
|
public double getMinGrade() {
|
||||||
|
return gradeExtremities.getMin();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum grade for this trip.
|
* Gets the maximum grade for this trip.
|
||||||
*
|
|
||||||
* @return The maximum grade for this trip as a fraction
|
|
||||||
*/
|
*/
|
||||||
public double getMaxGrade() {
|
public double getMaxGrade() {
|
||||||
return gradeExtremities.getMax();
|
return gradeExtremities.getMax();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the minimum grade for this trip.
|
* Sets the trip start time.
|
||||||
*
|
*
|
||||||
* @return The minimum grade for this trip as a fraction
|
* @param startTime the trip start time in milliseconds since the epoch
|
||||||
*/
|
|
||||||
public double getMinGrade() {
|
|
||||||
return gradeExtremities.getMin();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setters - to be used when restoring state or loading from the DB
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the start time for this trip.
|
|
||||||
*
|
|
||||||
* @param startTime the start time, in milliseconds since the epoch
|
|
||||||
*/
|
*/
|
||||||
public void setStartTime(long startTime) {
|
public void setStartTime(long startTime) {
|
||||||
this.startTime = startTime;
|
this.startTime = startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the stop time for this trip.
|
* Sets the trip stop time.
|
||||||
*
|
*
|
||||||
* @param stopTime the stop time, in milliseconds since the epoch
|
* @param stopTime the stop time in milliseconds since the epoch
|
||||||
*/
|
*/
|
||||||
public void setStopTime(long stopTime) {
|
public void setStopTime(long stopTime) {
|
||||||
this.stopTime = stopTime;
|
this.stopTime = stopTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the total moving time.
|
|
||||||
*
|
|
||||||
* @param movingTime the moving time in milliseconds
|
|
||||||
*/
|
|
||||||
public void setMovingTime(long movingTime) {
|
|
||||||
this.movingTime = movingTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the total trip time.
|
|
||||||
*
|
|
||||||
* @param totalTime the total trip time in milliseconds
|
|
||||||
*/
|
|
||||||
public void setTotalTime(long totalTime) {
|
|
||||||
this.totalTime = totalTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the total trip distance.
|
* Sets the total trip distance.
|
||||||
*
|
*
|
||||||
* @param totalDistance the trip distance in meters
|
* @param totalDistance the trip distance in meters
|
||||||
*/
|
*/
|
||||||
public void setTotalDistance(double totalDistance) {
|
public void setTotalDistance(double totalDistance) {
|
||||||
this.totalDistance = totalDistance;
|
this.totalDistance = totalDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the total elevation variation during the trip.
|
|
||||||
*
|
|
||||||
* @param totalElevationGain the elevation variation in meters
|
|
||||||
*/
|
|
||||||
public void setTotalElevationGain(double totalElevationGain) {
|
|
||||||
this.totalElevationGain = totalElevationGain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the maximum speed reached during the trip.
|
|
||||||
*
|
|
||||||
* @param maxSpeed the maximum speed in meters per second
|
|
||||||
*/
|
|
||||||
public void setMaxSpeed(double maxSpeed) {
|
|
||||||
this.maxSpeed = maxSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the minimum elevation reached during the trip.
|
|
||||||
*
|
|
||||||
* @param elevation the minimum elevation in meters
|
|
||||||
*/
|
|
||||||
public void setMinElevation(double elevation) {
|
|
||||||
elevationExtremities.setMin(elevation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the maximum elevation reached during the trip.
|
|
||||||
*
|
|
||||||
* @param elevation the maximum elevation in meters
|
|
||||||
*/
|
|
||||||
public void setMaxElevation(double elevation) {
|
|
||||||
elevationExtremities.setMax(elevation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the minimum grade obtained during the trip.
|
|
||||||
*
|
|
||||||
* @param grade the grade as a fraction (-1.0 would mean vertical downwards)
|
|
||||||
*/
|
|
||||||
public void setMinGrade(double grade) {
|
|
||||||
gradeExtremities.setMin(grade);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the maximum grade obtained during the trip).
|
|
||||||
*
|
|
||||||
* @param grade the grade as a fraction (1.0 would mean vertical upwards)
|
|
||||||
*/
|
|
||||||
public void setMaxGrade(double grade) {
|
|
||||||
gradeExtremities.setMax(grade);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the bounding box for this trip.
|
|
||||||
* The unit for all parameters is signed decimal degrees (degrees * 1E6).
|
|
||||||
*
|
|
||||||
* @param leftE6 the westmost longitude reached
|
|
||||||
* @param topE6 the northmost latitude reached
|
|
||||||
* @param rightE6 the eastmost longitude reached
|
|
||||||
* @param bottomE6 the southmost latitude reached
|
|
||||||
*/
|
|
||||||
public void setBounds(int leftE6, int topE6, int rightE6, int bottomE6) {
|
|
||||||
latitudeExtremities.set(bottomE6 / 1E6, topE6 / 1E6);
|
|
||||||
longitudeExtremities.set(leftE6 / 1E6, rightE6 / 1E6);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data manipulation methods
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds to the current total distance.
|
* Adds to the current total distance.
|
||||||
*
|
*
|
||||||
* @param distance the distance to add in meters
|
* @param distance the distance to add in meters
|
||||||
*/
|
*/
|
||||||
void addTotalDistance(double distance) {
|
void addTotalDistance(double distance) {
|
||||||
@@ -473,17 +333,26 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds to the total elevation variation.
|
* Sets the trip total time.
|
||||||
*
|
*
|
||||||
* @param gain the elevation variation in meters
|
* @param totalTime the trip total time in milliseconds
|
||||||
*/
|
*/
|
||||||
void addTotalElevationGain(double gain) {
|
public void setTotalTime(long totalTime) {
|
||||||
totalElevationGain += gain;
|
this.totalTime = totalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds to the total moving time of the trip.
|
* Sets the trip total moving time.
|
||||||
*
|
*
|
||||||
|
* @param movingTime the trip total moving time in milliseconds
|
||||||
|
*/
|
||||||
|
public void setMovingTime(long movingTime) {
|
||||||
|
this.movingTime = movingTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds to the trip total moving time.
|
||||||
|
*
|
||||||
* @param time the time in milliseconds
|
* @param time the time in milliseconds
|
||||||
*/
|
*/
|
||||||
void addMovingTime(long time) {
|
void addMovingTime(long time) {
|
||||||
@@ -491,8 +360,22 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accounts for a new latitude value for the bounding box.
|
* Sets the bounding box for this trip. The unit for all parameters is signed
|
||||||
*
|
* millions of degree (degrees * 1E6).
|
||||||
|
*
|
||||||
|
* @param leftE6 the leftmost longitude reached
|
||||||
|
* @param topE6 the topmost latitude reached
|
||||||
|
* @param rightE6 the rightmost longitude reached
|
||||||
|
* @param bottomE6 the bottommost latitude reached
|
||||||
|
*/
|
||||||
|
public void setBounds(int leftE6, int topE6, int rightE6, int bottomE6) {
|
||||||
|
latitudeExtremities.set(bottomE6 / 1E6, topE6 / 1E6);
|
||||||
|
longitudeExtremities.set(leftE6 / 1E6, rightE6 / 1E6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a new latitude value.
|
||||||
|
*
|
||||||
* @param latitude the latitude value in signed decimal degrees
|
* @param latitude the latitude value in signed decimal degrees
|
||||||
*/
|
*/
|
||||||
void updateLatitudeExtremities(double latitude) {
|
void updateLatitudeExtremities(double latitude) {
|
||||||
@@ -500,8 +383,8 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accounts for a new longitude value for the bounding box.
|
* Updates a new longitude value.
|
||||||
*
|
*
|
||||||
* @param longitude the longitude value in signed decimal degrees
|
* @param longitude the longitude value in signed decimal degrees
|
||||||
*/
|
*/
|
||||||
void updateLongitudeExtremities(double longitude) {
|
void updateLongitudeExtremities(double longitude) {
|
||||||
@@ -509,8 +392,35 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accounts for a new elevation value for the bounding box.
|
* Sets the maximum speed.
|
||||||
*
|
*
|
||||||
|
* @param maxSpeed the maximum speed in meters/second
|
||||||
|
*/
|
||||||
|
public void setMaxSpeed(double maxSpeed) {
|
||||||
|
this.maxSpeed = maxSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimum elevation.
|
||||||
|
*
|
||||||
|
* @param elevation the minimum elevation in meters
|
||||||
|
*/
|
||||||
|
public void setMinElevation(double elevation) {
|
||||||
|
elevationExtremities.setMin(elevation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum elevation.
|
||||||
|
*
|
||||||
|
* @param elevation the maximum elevation in meters
|
||||||
|
*/
|
||||||
|
public void setMaxElevation(double elevation) {
|
||||||
|
elevationExtremities.setMax(elevation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a new elevation.
|
||||||
|
*
|
||||||
* @param elevation the elevation value in meters
|
* @param elevation the elevation value in meters
|
||||||
*/
|
*/
|
||||||
void updateElevationExtremities(double elevation) {
|
void updateElevationExtremities(double elevation) {
|
||||||
@@ -518,49 +428,77 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accounts for a new grade value.
|
* Sets the total elevation gain.
|
||||||
*
|
*
|
||||||
|
* @param totalElevationGain the elevation gain in meters
|
||||||
|
*/
|
||||||
|
public void setTotalElevationGain(double totalElevationGain) {
|
||||||
|
this.totalElevationGain = totalElevationGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds to the total elevation gain.
|
||||||
|
*
|
||||||
|
* @param gain the elevation gain in meters
|
||||||
|
*/
|
||||||
|
void addTotalElevationGain(double gain) {
|
||||||
|
totalElevationGain += gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimum grade.
|
||||||
|
*
|
||||||
|
* @param grade the grade as a fraction (-1.0 would mean vertical downwards)
|
||||||
|
*/
|
||||||
|
public void setMinGrade(double grade) {
|
||||||
|
gradeExtremities.setMin(grade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum grade.
|
||||||
|
*
|
||||||
|
* @param grade the grade as a fraction (1.0 would mean vertical upwards)
|
||||||
|
*/
|
||||||
|
public void setMaxGrade(double grade) {
|
||||||
|
gradeExtremities.setMax(grade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a new grade value.
|
||||||
|
*
|
||||||
* @param grade the grade value as a fraction
|
* @param grade the grade value as a fraction
|
||||||
*/
|
*/
|
||||||
void updateGradeExtremities(double grade) {
|
void updateGradeExtremities(double grade) {
|
||||||
gradeExtremities.update(grade);
|
gradeExtremities.update(grade);
|
||||||
}
|
}
|
||||||
|
|
||||||
// String conversion
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TripStatistics { Start Time: " + getStartTime()
|
return "TripStatistics { Start Time: " + getStartTime() + "; Stop Time: " + getStopTime()
|
||||||
+ "; Total Time: " + getTotalTime()
|
+ "; Total Time: " + getTotalTime() + "; Total Distance: " + getTotalDistance()
|
||||||
+ "; Moving Time: " + getMovingTime()
|
+ "; Total Time: " + getTotalTime() + "; Moving Time: " + getMovingTime()
|
||||||
+ "; Total Distance: " + getTotalDistance()
|
+ "; Min Latitude: " + getBottomDegrees() + "; Max Latitude: " + getTopDegrees()
|
||||||
+ "; Elevation Gain: " + getTotalElevationGain()
|
+ "; Min Longitude: " + getLeftDegrees() + "; Max Longitude: " + getRightDegrees()
|
||||||
+ "; Min Elevation: " + getMinElevation()
|
+ "; Max Elevation: " + getMaxElevation() + "; Max Speed: " + getMaxSpeed()
|
||||||
+ "; Max Elevation: " + getMaxElevation()
|
+ "; Min Elevation: " + getMinElevation() + "; Max Elevation: " + getMaxElevation()
|
||||||
+ "; Average Speed: " + getAverageMovingSpeed()
|
+ "; Elevation Gain: " + getTotalElevationGain() + "; Min Grade: " + getMinGrade()
|
||||||
+ "; Min Grade: " + getMinGrade()
|
+ "; Max Grade: " + getMaxGrade() + "}";
|
||||||
+ "; Max Grade: " + getMaxGrade()
|
|
||||||
+ "}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parcelable interface and creator
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creator of statistics data from parcels.
|
* Creator of statistics data from parcels.
|
||||||
*/
|
*/
|
||||||
public static class Creator
|
public static class Creator implements Parcelable.Creator<TripStatistics> {
|
||||||
implements Parcelable.Creator<TripStatistics> {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TripStatistics createFromParcel(Parcel source) {
|
public TripStatistics createFromParcel(Parcel source) {
|
||||||
TripStatistics data = new TripStatistics();
|
TripStatistics data = new TripStatistics();
|
||||||
|
|
||||||
data.startTime = source.readLong();
|
data.startTime = source.readLong();
|
||||||
data.movingTime = source.readLong();
|
data.stopTime = source.readLong();
|
||||||
data.totalTime = source.readLong();
|
|
||||||
data.totalDistance = source.readDouble();
|
data.totalDistance = source.readDouble();
|
||||||
data.totalElevationGain = source.readDouble();
|
data.totalTime = source.readLong();
|
||||||
data.maxSpeed = source.readDouble();
|
data.movingTime = source.readLong();
|
||||||
|
|
||||||
double minLat = source.readDouble();
|
double minLat = source.readDouble();
|
||||||
double maxLat = source.readDouble();
|
double maxLat = source.readDouble();
|
||||||
@@ -570,9 +508,12 @@ public class TripStatistics implements Parcelable {
|
|||||||
double maxLong = source.readDouble();
|
double maxLong = source.readDouble();
|
||||||
data.longitudeExtremities.set(minLong, maxLong);
|
data.longitudeExtremities.set(minLong, maxLong);
|
||||||
|
|
||||||
|
data.maxSpeed = source.readDouble();
|
||||||
|
|
||||||
double minElev = source.readDouble();
|
double minElev = source.readDouble();
|
||||||
double maxElev = source.readDouble();
|
double maxElev = source.readDouble();
|
||||||
data.elevationExtremities.set(minElev, maxElev);
|
data.elevationExtremities.set(minElev, maxElev);
|
||||||
|
data.totalElevationGain = source.readDouble();
|
||||||
|
|
||||||
double minGrade = source.readDouble();
|
double minGrade = source.readDouble();
|
||||||
double maxGrade = source.readDouble();
|
double maxGrade = source.readDouble();
|
||||||
@@ -600,18 +541,18 @@ public class TripStatistics implements Parcelable {
|
|||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeLong(startTime);
|
dest.writeLong(startTime);
|
||||||
dest.writeLong(movingTime);
|
dest.writeLong(stopTime);
|
||||||
dest.writeLong(totalTime);
|
|
||||||
dest.writeDouble(totalDistance);
|
dest.writeDouble(totalDistance);
|
||||||
dest.writeDouble(totalElevationGain);
|
dest.writeLong(totalTime);
|
||||||
dest.writeDouble(maxSpeed);
|
dest.writeLong(movingTime);
|
||||||
|
|
||||||
dest.writeDouble(latitudeExtremities.getMin());
|
dest.writeDouble(latitudeExtremities.getMin());
|
||||||
dest.writeDouble(latitudeExtremities.getMax());
|
dest.writeDouble(latitudeExtremities.getMax());
|
||||||
dest.writeDouble(longitudeExtremities.getMin());
|
dest.writeDouble(longitudeExtremities.getMin());
|
||||||
dest.writeDouble(longitudeExtremities.getMax());
|
dest.writeDouble(longitudeExtremities.getMax());
|
||||||
|
dest.writeDouble(maxSpeed);
|
||||||
dest.writeDouble(elevationExtremities.getMin());
|
dest.writeDouble(elevationExtremities.getMin());
|
||||||
dest.writeDouble(elevationExtremities.getMax());
|
dest.writeDouble(elevationExtremities.getMax());
|
||||||
|
dest.writeDouble(totalElevationGain);
|
||||||
dest.writeDouble(gradeExtremities.getMin());
|
dest.writeDouble(gradeExtremities.getMin());
|
||||||
dest.writeDouble(gradeExtremities.getMax());
|
dest.writeDouble(gradeExtremities.getMax());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ limitations under the License.
|
|||||||
<instrumentation
|
<instrumentation
|
||||||
android:name="android.test.InstrumentationTestRunner"
|
android:name="android.test.InstrumentationTestRunner"
|
||||||
android:targetPackage="com.google.android.maps.mytracks" />
|
android:targetPackage="com.google.android.maps.mytracks" />
|
||||||
|
|
||||||
|
<instrumentation
|
||||||
|
android:name="com.google.android.apps.mytracks.endtoendtest.EndToEndTestRunner"
|
||||||
|
android:targetPackage="com.google.android.maps.mytracks" />
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="7"
|
android:minSdkVersion="7"
|
||||||
|
|||||||
+41
-33
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.content;
|
|||||||
import com.google.android.apps.mytracks.content.MyTracksProvider.DatabaseHelper;
|
import com.google.android.apps.mytracks.content.MyTracksProvider.DatabaseHelper;
|
||||||
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.net.Uri;
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,10 +30,13 @@ public class MyTracksProviderTest extends AndroidTestCase {
|
|||||||
|
|
||||||
private SQLiteDatabase db;
|
private SQLiteDatabase db;
|
||||||
private MyTracksProvider myTracksProvider;
|
private MyTracksProvider myTracksProvider;
|
||||||
|
private String DATABASE_NAME = "mytrackstest.db";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
recreatedDatabase();
|
getContext().deleteDatabase(DATABASE_NAME);
|
||||||
|
db = (new DatabaseHelper(getContext(), DATABASE_NAME)).getWritableDatabase();
|
||||||
|
|
||||||
myTracksProvider = new MyTracksProvider();
|
myTracksProvider = new MyTracksProvider();
|
||||||
super.setUp();
|
super.setUp();
|
||||||
}
|
}
|
||||||
@@ -61,7 +65,7 @@ public class MyTracksProviderTest extends AndroidTestCase {
|
|||||||
assertTrue(checkTable(TracksColumns.TABLE_NAME));
|
assertTrue(checkTable(TracksColumns.TABLE_NAME));
|
||||||
assertTrue(checkTable(WaypointsColumns.TABLE_NAME));
|
assertTrue(checkTable(WaypointsColumns.TABLE_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method
|
* Tests the method
|
||||||
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
|
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
|
||||||
@@ -69,18 +73,18 @@ public class MyTracksProviderTest extends AndroidTestCase {
|
|||||||
*/
|
*/
|
||||||
public void testDatabaseHelper_onUpgrade_Version17() {
|
public void testDatabaseHelper_onUpgrade_Version17() {
|
||||||
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
|
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
|
||||||
|
|
||||||
// Make two table is only contains one normal integer column.
|
// Make two table is only contains one normal integer column.
|
||||||
dropTable(TrackPointsColumns.TABLE_NAME);
|
dropTable(TrackPointsColumns.TABLE_NAME);
|
||||||
dropTable(TracksColumns.TABLE_NAME);
|
dropTable(TracksColumns.TABLE_NAME);
|
||||||
createEmptyTable(TrackPointsColumns.TABLE_NAME);
|
createEmptyTable(TrackPointsColumns.TABLE_NAME);
|
||||||
createEmptyTable(TracksColumns.TABLE_NAME);
|
createEmptyTable(TracksColumns.TABLE_NAME);
|
||||||
databaseHelper.onUpgrade(db, 17, 20);
|
databaseHelper.onUpgrade(db, 17, 20);
|
||||||
assertTrue(checkColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
|
assertTrue(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
|
||||||
assertTrue(checkColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
|
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
|
||||||
assertTrue(checkColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
|
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method
|
* Tests the method
|
||||||
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
|
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
|
||||||
@@ -88,18 +92,18 @@ public class MyTracksProviderTest extends AndroidTestCase {
|
|||||||
*/
|
*/
|
||||||
public void testDatabaseHelper_onUpgrade_Version18() {
|
public void testDatabaseHelper_onUpgrade_Version18() {
|
||||||
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
|
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
|
||||||
|
|
||||||
// Make two table is only contains one normal integer column.
|
// Make two table is only contains one normal integer column.
|
||||||
dropTable(TrackPointsColumns.TABLE_NAME);
|
dropTable(TrackPointsColumns.TABLE_NAME);
|
||||||
dropTable(TracksColumns.TABLE_NAME);
|
dropTable(TracksColumns.TABLE_NAME);
|
||||||
createEmptyTable(TrackPointsColumns.TABLE_NAME);
|
createEmptyTable(TrackPointsColumns.TABLE_NAME);
|
||||||
createEmptyTable(TracksColumns.TABLE_NAME);
|
createEmptyTable(TracksColumns.TABLE_NAME);
|
||||||
databaseHelper.onUpgrade(db, 18, 20);
|
databaseHelper.onUpgrade(db, 18, 20);
|
||||||
assertFalse(checkColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
|
assertFalse(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
|
||||||
assertTrue(checkColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
|
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
|
||||||
assertTrue(checkColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
|
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method
|
* Tests the method
|
||||||
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
|
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)}
|
||||||
@@ -107,16 +111,16 @@ public class MyTracksProviderTest extends AndroidTestCase {
|
|||||||
*/
|
*/
|
||||||
public void testDatabaseHelper_onUpgrade_Version19() {
|
public void testDatabaseHelper_onUpgrade_Version19() {
|
||||||
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
|
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
|
||||||
|
|
||||||
// Make two table is only contains one normal integer column.
|
// Make two table is only contains one normal integer column.
|
||||||
dropTable(TrackPointsColumns.TABLE_NAME);
|
dropTable(TrackPointsColumns.TABLE_NAME);
|
||||||
dropTable(TracksColumns.TABLE_NAME);
|
dropTable(TracksColumns.TABLE_NAME);
|
||||||
createEmptyTable(TrackPointsColumns.TABLE_NAME);
|
createEmptyTable(TrackPointsColumns.TABLE_NAME);
|
||||||
createEmptyTable(TracksColumns.TABLE_NAME);
|
createEmptyTable(TracksColumns.TABLE_NAME);
|
||||||
databaseHelper.onUpgrade(db, 19, 20);
|
databaseHelper.onUpgrade(db, 19, 20);
|
||||||
assertFalse(checkColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
|
assertFalse(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
|
||||||
assertFalse(checkColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
|
assertFalse(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
|
||||||
assertTrue(checkColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
|
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,11 +131,14 @@ public class MyTracksProviderTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recreates the database of MyTracks.
|
* Tests the method {@link MyTracksProvider#getType(Uri)}.
|
||||||
*/
|
*/
|
||||||
private void recreatedDatabase() {
|
public void testGetType() {
|
||||||
assertTrue(getContext().deleteDatabase(MyTracksProvider.DATABASE_NAME));
|
assertEquals(TrackPointsColumns.CONTENT_TYPE,
|
||||||
db = (new DatabaseHelper(getContext())).getWritableDatabase();
|
myTracksProvider.getType(TrackPointsColumns.CONTENT_URI));
|
||||||
|
assertEquals(TracksColumns.CONTENT_TYPE, myTracksProvider.getType(TracksColumns.CONTENT_URI));
|
||||||
|
assertEquals(WaypointsColumns.CONTENT_TYPE,
|
||||||
|
myTracksProvider.getType(WaypointsColumns.CONTENT_URI));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,17 +147,18 @@ public class MyTracksProviderTest extends AndroidTestCase {
|
|||||||
* @param table the name of table
|
* @param table the name of table
|
||||||
*/
|
*/
|
||||||
private void createEmptyTable(String table) {
|
private void createEmptyTable(String table) {
|
||||||
db.execSQL( "CREATE TABLE " + table + " (test INTEGER)");
|
db.execSQL("CREATE TABLE " + table + " (test INTEGER)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drops a table in database.
|
* Drops a table in database.
|
||||||
|
*
|
||||||
* @param table
|
* @param table
|
||||||
*/
|
*/
|
||||||
private void dropTable(String table) {
|
private void dropTable(String table) {
|
||||||
db.execSQL("Drop TABLE " + table);
|
db.execSQL("Drop TABLE " + table);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a table is existed.
|
* Checks whether a table is existed.
|
||||||
*
|
*
|
||||||
@@ -162,27 +170,27 @@ public class MyTracksProviderTest extends AndroidTestCase {
|
|||||||
db.rawQuery("select count(*) from " + table, null);
|
db.rawQuery("select count(*) from " + table, null);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a column in a table is existed.
|
* Checks whether a column in a table is existed by whether can order by the
|
||||||
|
* column.
|
||||||
*
|
*
|
||||||
* @param table the name of table
|
* @param table the name of table
|
||||||
* @param column the name of column
|
* @param column the name of column
|
||||||
* @return true means the column has existed
|
* @return true means the column has existed
|
||||||
*/
|
*/
|
||||||
private boolean checkColumn(String table, String column) {
|
private boolean isColumnExisted(String table, String column) {
|
||||||
try {
|
try {
|
||||||
db.execSQL("ALTER TABLE " + table + " add " + column);
|
db.execSQL("SElECT count(*) from " + table + " order by " + column);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if(e.getMessage().indexOf("duplicate column") > -1) {
|
if (e.getMessage().indexOf("no such column") > -1) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+30
-2
@@ -430,7 +430,7 @@ public class MyTracksProviderUtilsImplTest extends AndroidTestCase {
|
|||||||
/**
|
/**
|
||||||
* Tests the method {@link MyTracksProviderUtilsImpl#getLastWaypointId(long)}.
|
* Tests the method {@link MyTracksProviderUtilsImpl#getLastWaypointId(long)}.
|
||||||
*/
|
*/
|
||||||
public void testGetKLastWaypointId() {
|
public void testGetLastWaypointId() {
|
||||||
long trackId = System.currentTimeMillis();
|
long trackId = System.currentTimeMillis();
|
||||||
Track track = getTrack(trackId, 10);
|
Track track = getTrack(trackId, 10);
|
||||||
providerUtils.insertTrack(track);
|
providerUtils.insertTrack(track);
|
||||||
@@ -448,7 +448,35 @@ public class MyTracksProviderUtilsImplTest extends AndroidTestCase {
|
|||||||
assertEquals(-1L, providerUtils.getLastWaypointId(-1));
|
assertEquals(-1L, providerUtils.getLastWaypointId(-1));
|
||||||
assertEquals(3L, providerUtils.getLastWaypointId(trackId));
|
assertEquals(3L, providerUtils.getLastWaypointId(trackId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the method
|
||||||
|
* {@link MyTracksProviderUtils#getLastStatisticsWaypoint(long)}.
|
||||||
|
*/
|
||||||
|
public void testGetLastStatisticsWaypoint() {
|
||||||
|
long trackId = System.currentTimeMillis();
|
||||||
|
Track track = getTrack(trackId, 10);
|
||||||
|
providerUtils.insertTrack(track);
|
||||||
|
|
||||||
|
Waypoint waypoint1 = new Waypoint();
|
||||||
|
waypoint1.setTrackId(trackId);
|
||||||
|
waypoint1.setType(Waypoint.TYPE_STATISTICS);
|
||||||
|
waypoint1.setDescription("Desc1");
|
||||||
|
Waypoint waypoint2 = new Waypoint();
|
||||||
|
waypoint2.setTrackId(trackId);
|
||||||
|
waypoint2.setType(Waypoint.TYPE_STATISTICS);
|
||||||
|
waypoint2.setDescription("Desc2");
|
||||||
|
Waypoint waypoint3 = new Waypoint();
|
||||||
|
waypoint3.setTrackId(trackId);
|
||||||
|
waypoint3.setType(Waypoint.TYPE_WAYPOINT);
|
||||||
|
waypoint3.setDescription("Desc3");
|
||||||
|
providerUtils.insertWaypoint(waypoint1);
|
||||||
|
providerUtils.insertWaypoint(waypoint2);
|
||||||
|
providerUtils.insertWaypoint(waypoint3);
|
||||||
|
|
||||||
|
assertEquals("Desc2", providerUtils.getLastStatisticsWaypoint(trackId).getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link MyTracksProviderUtilsImpl#getNextMarkerNumber(long, boolean)}.
|
* Tests the method {@link MyTracksProviderUtilsImpl#getNextMarkerNumber(long, boolean)}.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+8
-8
@@ -246,7 +246,8 @@ public class CreateAndSendTrackTest extends ActivityInstrumentationTestCase2<Tra
|
|||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
EndToEndTestUtils.stopRecording(false);
|
EndToEndTestUtils.stopRecording(false);
|
||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.generic_save));
|
EndToEndTestUtils.getButtonOnScreen(activityMyTracks.getString(R.string.generic_save), true,
|
||||||
|
true);
|
||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
EndToEndTestUtils.SOLO.goBack();
|
EndToEndTestUtils.SOLO.goBack();
|
||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
@@ -261,8 +262,9 @@ public class CreateAndSendTrackTest extends ActivityInstrumentationTestCase2<Tra
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests whether the split marker is created as setting.
|
* Tests whether the split marker is created as setting.
|
||||||
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
public void testSplitSetting() {
|
public void testSplitSetting() throws InterruptedException {
|
||||||
EndToEndTestUtils.startRecording();
|
EndToEndTestUtils.startRecording();
|
||||||
|
|
||||||
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_split_frequency), true);
|
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_split_frequency), true);
|
||||||
@@ -276,9 +278,9 @@ public class CreateAndSendTrackTest extends ActivityInstrumentationTestCase2<Tra
|
|||||||
EndToEndTestUtils
|
EndToEndTestUtils
|
||||||
.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
|
.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
|
||||||
// Send Gps to give a distance more than one kilometer or one mile.
|
// Send Gps to give a distance more than one kilometer or one mile.
|
||||||
EndToEndTestUtils.sendGps(20);
|
EndToEndTestUtils.sendGps(20);
|
||||||
|
assertTrue(EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_markers),
|
||||||
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_markers), true);
|
true));
|
||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
if (EndToEndTestUtils.hasGpsSingal) {
|
if (EndToEndTestUtils.hasGpsSingal) {
|
||||||
assertTrue(EndToEndTestUtils.SOLO.getCurrentListViews().get(0).getCount() > 0);
|
assertTrue(EndToEndTestUtils.SOLO.getCurrentListViews().get(0).getCount() > 0);
|
||||||
@@ -297,12 +299,10 @@ public class CreateAndSendTrackTest extends ActivityInstrumentationTestCase2<Tra
|
|||||||
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_markers), true);
|
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_markers), true);
|
||||||
EndToEndTestUtils.SOLO.waitForText(activityMyTracks.getString(R.string.marker_list_empty_message));
|
EndToEndTestUtils.SOLO.waitForText(activityMyTracks.getString(R.string.marker_list_empty_message));
|
||||||
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_insert_marker), true);
|
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_insert_marker), true);
|
||||||
// Rotate when show insert page.
|
|
||||||
EndToEndTestUtils.rotateAllActivities();
|
|
||||||
EndToEndTestUtils.enterTextAvoidSoftKeyBoard(0, WAYPOINT_NAME);
|
EndToEndTestUtils.enterTextAvoidSoftKeyBoard(0, WAYPOINT_NAME);
|
||||||
EndToEndTestUtils.SOLO.clickOnButton(activityMyTracks.getString(R.string.generic_add));
|
EndToEndTestUtils.SOLO.clickOnButton(activityMyTracks.getString(R.string.generic_add));
|
||||||
if (EndToEndTestUtils.hasGpsSingal) {
|
if (EndToEndTestUtils.hasGpsSingal) {
|
||||||
assertTrue(EndToEndTestUtils.SOLO.searchText(WAYPOINT_NAME));
|
assertTrue(EndToEndTestUtils.SOLO.waitForText(WAYPOINT_NAME, 1, EndToEndTestUtils.LONG_WAIT_TIME, true));
|
||||||
} else {
|
} else {
|
||||||
assertFalse(EndToEndTestUtils.SOLO.searchText(WAYPOINT_NAME));
|
assertFalse(EndToEndTestUtils.SOLO.searchText(WAYPOINT_NAME));
|
||||||
}
|
}
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.apps.mytracks.endtoendtest;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.test.InstrumentationTestRunner;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test runner can be used to run end-to-end test.
|
||||||
|
*
|
||||||
|
* @author Youtao Liu
|
||||||
|
*/
|
||||||
|
public class EndToEndTestRunner extends InstrumentationTestRunner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parameter port which is used to fix GPS signal to emulators.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle arguments) {
|
||||||
|
try {
|
||||||
|
EndToEndTestUtils.emulatorPort = Integer.parseInt(arguments.getString("port"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(EndToEndTestUtils.LOG_TAG, "Unable to get port parameter, use default value." + EndToEndTestUtils.emulatorPort, e);
|
||||||
|
}
|
||||||
|
Log.d(EndToEndTestUtils.LOG_TAG, "Use port number when run test on emulator:" + EndToEndTestUtils.emulatorPort);
|
||||||
|
|
||||||
|
super.onCreate(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+68
-46
@@ -25,6 +25,7 @@ import android.app.Activity;
|
|||||||
import android.app.Instrumentation;
|
import android.app.Instrumentation;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
@@ -41,6 +42,7 @@ import java.net.Socket;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides utilities to smoke test.
|
* Provides utilities to smoke test.
|
||||||
@@ -51,7 +53,7 @@ public class EndToEndTestUtils {
|
|||||||
|
|
||||||
private static final String ANDROID_LOCAL_IP = "10.0.2.2";
|
private static final String ANDROID_LOCAL_IP = "10.0.2.2";
|
||||||
// usually 5554.
|
// usually 5554.
|
||||||
private static final int ANDROID_LOCAL_PORT = 5554;
|
public static int emulatorPort = 5558;
|
||||||
|
|
||||||
private static final int ORIENTATION_PORTRAIT = 1;
|
private static final int ORIENTATION_PORTRAIT = 1;
|
||||||
private static final int ORIENTATION_LANDSCAPE = 0;
|
private static final int ORIENTATION_LANDSCAPE = 0;
|
||||||
@@ -127,6 +129,7 @@ public class EndToEndTestUtils {
|
|||||||
static boolean isEmulator = true;
|
static boolean isEmulator = true;
|
||||||
static boolean hasGpsSingal = true;
|
static boolean hasGpsSingal = true;
|
||||||
static boolean isCheckedFirstLaunch = false;
|
static boolean isCheckedFirstLaunch = false;
|
||||||
|
public static final String LOG_TAG = "MyTracksTest";
|
||||||
|
|
||||||
private EndToEndTestUtils() {}
|
private EndToEndTestUtils() {}
|
||||||
|
|
||||||
@@ -134,6 +137,14 @@ public class EndToEndTestUtils {
|
|||||||
* Checks the language, then sets the fields with right string.
|
* Checks the language, then sets the fields with right string.
|
||||||
*/
|
*/
|
||||||
private static void checkLanguage() {
|
private static void checkLanguage() {
|
||||||
|
Locale locale = null;
|
||||||
|
Configuration config=null;
|
||||||
|
config = activityMytracks.getBaseContext().getResources().getConfiguration();
|
||||||
|
locale = new Locale("en");
|
||||||
|
Locale.setDefault(locale);
|
||||||
|
config.locale = locale;
|
||||||
|
|
||||||
|
|
||||||
deviceLanguage = instrumentation.getContext().getResources().getConfiguration().locale.getLanguage();
|
deviceLanguage = instrumentation.getContext().getResources().getConfiguration().locale.getLanguage();
|
||||||
if (RELATIVE_STARTTIME_POSTFIX_MULTILINGUAL.get(deviceLanguage) != null) {
|
if (RELATIVE_STARTTIME_POSTFIX_MULTILINGUAL.get(deviceLanguage) != null) {
|
||||||
RELATIVE_STARTTIME_POSTFIX = RELATIVE_STARTTIME_POSTFIX_MULTILINGUAL.get(deviceLanguage);
|
RELATIVE_STARTTIME_POSTFIX = RELATIVE_STARTTIME_POSTFIX_MULTILINGUAL.get(deviceLanguage);
|
||||||
@@ -165,7 +176,7 @@ public class EndToEndTestUtils {
|
|||||||
PrintStream out = null;
|
PrintStream out = null;
|
||||||
Socket socket = null;
|
Socket socket = null;
|
||||||
try {
|
try {
|
||||||
socket = new Socket(ANDROID_LOCAL_IP, ANDROID_LOCAL_PORT);
|
socket = new Socket(ANDROID_LOCAL_IP, emulatorPort);
|
||||||
out = new PrintStream(socket.getOutputStream());
|
out = new PrintStream(socket.getOutputStream());
|
||||||
float longitude = START_LONGITUDE;
|
float longitude = START_LONGITUDE;
|
||||||
float latitude = START_LATITUDE;
|
float latitude = START_LATITUDE;
|
||||||
@@ -175,6 +186,8 @@ public class EndToEndTestUtils {
|
|||||||
longitude += DELTA_LONGITUDE;
|
longitude += DELTA_LONGITUDE;
|
||||||
latitude += DELTA_LADITUDE;
|
latitude += DELTA_LADITUDE;
|
||||||
}
|
}
|
||||||
|
// Wait the GPS signal can be obtained by MyTracks.
|
||||||
|
Thread.sleep(SHORT_WAIT_TIME);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
System.exit(-1);
|
System.exit(-1);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -406,8 +419,8 @@ public class EndToEndTestUtils {
|
|||||||
trackName = TRACK_NAME_PREFIX
|
trackName = TRACK_NAME_PREFIX
|
||||||
+ System.currentTimeMillis();
|
+ System.currentTimeMillis();
|
||||||
SOLO.sendKey(KeyEvent.KEYCODE_DEL);
|
SOLO.sendKey(KeyEvent.KEYCODE_DEL);
|
||||||
SOLO.enterText(0, trackName);
|
enterTextAvoidSoftKeyBoard(0, trackName);
|
||||||
SOLO.enterText(1, DEFAULTACTIVITY);
|
enterTextAvoidSoftKeyBoard(1, DEFAULTACTIVITY);
|
||||||
SOLO.clickOnText(activityMytracks.getString(R.string.generic_save));
|
SOLO.clickOnText(activityMytracks.getString(R.string.generic_save));
|
||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
}
|
}
|
||||||
@@ -485,6 +498,7 @@ public class EndToEndTestUtils {
|
|||||||
SOLO.waitForText(buttonName);
|
SOLO.waitForText(buttonName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find on action bar.
|
||||||
if (hasActionBar) {
|
if (hasActionBar) {
|
||||||
ArrayList<View> allViews = SOLO.getViews();
|
ArrayList<View> allViews = SOLO.getViews();
|
||||||
for (View view : allViews) {
|
for (View view : allViews) {
|
||||||
@@ -499,18 +513,25 @@ public class EndToEndTestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<Button> currentButtons = SOLO.getCurrentButtons();
|
// Get all buttons and find.
|
||||||
for (Button oneButton : currentButtons) {
|
if(button == null) {
|
||||||
String title = (String) oneButton.getText();
|
ArrayList<Button> currentButtons = SOLO.getCurrentButtons();
|
||||||
if (title.equalsIgnoreCase(buttonName)) {
|
for (Button oneButton : currentButtons) {
|
||||||
button = oneButton;
|
String title = (String) oneButton.getText();
|
||||||
|
if (title.equalsIgnoreCase(buttonName)) {
|
||||||
|
button = oneButton;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isClick) {
|
if(button != null && isClick) {
|
||||||
SOLO.clickOnView(button);
|
SOLO.clickOnView(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (button == null && isClick) {
|
||||||
|
Log.d(LOG_TAG, "Don't find the button " + buttonName);
|
||||||
|
}
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,48 +577,49 @@ public class EndToEndTestUtils {
|
|||||||
* @param click true means need click this menu
|
* @param click true means need click this menu
|
||||||
* @return true if find this menu
|
* @return true if find this menu
|
||||||
*/
|
*/
|
||||||
static boolean findMenuItem(String menuName, boolean click) {boolean findResult = false;
|
static boolean findMenuItem(String menuName, boolean click) {
|
||||||
boolean isMoreMenuOpened = false;
|
boolean findResult = false;
|
||||||
|
boolean isMoreMenuOpened = false;
|
||||||
// ICS phone.
|
|
||||||
if(hasActionBar) {
|
// ICS phone.
|
||||||
// Firstly find in action bar.
|
if (hasActionBar) {
|
||||||
View button = getButtonOnScreen(menuName, false, false);
|
// Firstly find in action bar.
|
||||||
if (button != null) {
|
View button = getButtonOnScreen(menuName, false, false);
|
||||||
findResult = true;
|
if (button != null) {
|
||||||
if (click) {
|
findResult = true;
|
||||||
SOLO.clickOnView(button);
|
if (click) {
|
||||||
instrumentation.waitForIdleSync();
|
SOLO.clickOnView(button);
|
||||||
|
instrumentation.waitForIdleSync();
|
||||||
|
}
|
||||||
|
return findResult;
|
||||||
}
|
}
|
||||||
return findResult;
|
showMenuItem();
|
||||||
}
|
|
||||||
showMenuItem();
|
|
||||||
findResult = SOLO.searchText(menuName);
|
|
||||||
} else {
|
|
||||||
// Non-ICS phone.
|
|
||||||
SOLO.sendKey(KeyEvent.KEYCODE_MENU);
|
|
||||||
if (SOLO.searchText(menuName)) {
|
|
||||||
findResult = true;
|
|
||||||
} else if (SOLO.searchText(MENU_MORE)) {
|
|
||||||
SOLO.clickOnText(MENU_MORE);
|
|
||||||
findResult = SOLO.searchText(menuName);
|
findResult = SOLO.searchText(menuName);
|
||||||
isMoreMenuOpened = true;
|
} else {
|
||||||
|
// Non-ICS phone.
|
||||||
|
SOLO.sendKey(KeyEvent.KEYCODE_MENU);
|
||||||
|
if (SOLO.searchText(menuName)) {
|
||||||
|
findResult = true;
|
||||||
|
} else if (SOLO.searchText(MENU_MORE)) {
|
||||||
|
SOLO.clickOnText(MENU_MORE);
|
||||||
|
findResult = SOLO.searchText(menuName);
|
||||||
|
isMoreMenuOpened = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (findResult && click) {
|
||||||
if (findResult && click) {
|
SOLO.clickOnText(menuName);
|
||||||
SOLO.clickOnText(menuName);
|
instrumentation.waitForIdleSync();
|
||||||
instrumentation.waitForIdleSync();
|
} else {
|
||||||
} else {
|
// Quit more menu list if opened.
|
||||||
// Quit more menu list if opened.
|
if (isMoreMenuOpened) {
|
||||||
if (isMoreMenuOpened) {
|
SOLO.goBack();
|
||||||
|
}
|
||||||
|
// Quit menu list.
|
||||||
SOLO.goBack();
|
SOLO.goBack();
|
||||||
}
|
}
|
||||||
// Quit menu list.
|
return findResult;
|
||||||
SOLO.goBack();
|
|
||||||
}
|
}
|
||||||
return findResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show menu item list.
|
* Show menu item list.
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ import java.util.Locale;
|
|||||||
* @author Youtao Liu
|
* @author Youtao Liu
|
||||||
*/
|
*/
|
||||||
public class GoogleUtils {
|
public class GoogleUtils {
|
||||||
public static final String LOG_TAG = "MyTracksTest";
|
|
||||||
public static final String DOCUMENT_NAME_PREFIX = "My Tracks";
|
public static final String DOCUMENT_NAME_PREFIX = "My Tracks";
|
||||||
public static final String SPREADSHEET_NAME = DOCUMENT_NAME_PREFIX + "-" + EndToEndTestUtils.DEFAULTACTIVITY;
|
public static final String SPREADSHEET_NAME = DOCUMENT_NAME_PREFIX + "-" + EndToEndTestUtils.DEFAULTACTIVITY;
|
||||||
|
|
||||||
@@ -92,7 +91,7 @@ public class GoogleUtils {
|
|||||||
authToken = AccountManager.get(context).blockingGetAuthToken(getAccount(context),
|
authToken = AccountManager.get(context).blockingGetAuthToken(getAccount(context),
|
||||||
MapsConstants.SERVICE_NAME, false);
|
MapsConstants.SERVICE_NAME, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(LOG_TAG, "Unable to get auth token", e);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Unable to get auth token", e);
|
||||||
return mapData;
|
return mapData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +106,7 @@ public class GoogleUtils {
|
|||||||
mapData.add(MapsGDataConverter.getMapMetadataForEntry(entry));
|
mapData.add(MapsGDataConverter.getMapMetadataForEntry(entry));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(LOG_TAG, "Unable to get maps", e);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Unable to get maps", e);
|
||||||
} finally {
|
} finally {
|
||||||
if (gDataParser != null) {
|
if (gDataParser != null) {
|
||||||
gDataParser.close();
|
gDataParser.close();
|
||||||
@@ -139,7 +138,7 @@ public class GoogleUtils {
|
|||||||
MapsConstants.SERVICE_NAME, false));
|
MapsConstants.SERVICE_NAME, false));
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(LOG_TAG, "Unable to drop map", e);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Unable to drop map", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +200,7 @@ public class GoogleUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(LOG_TAG, "Unable to fetch spreadsheet.", e);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Unable to fetch spreadsheet.", e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -219,7 +218,7 @@ public class GoogleUtils {
|
|||||||
private static boolean searchTrackTitleInSpreadsheet(String title, Activity activity, String spreadsheetTitle, boolean isDelete) {
|
private static boolean searchTrackTitleInSpreadsheet(String title, Activity activity, String spreadsheetTitle, boolean isDelete) {
|
||||||
String spreadsheetId = searchSpreadsheetByTitle(spreadsheetTitle, activity).getId().replace(SendDocsUtils.SPREADSHEET_ID_PREFIX, "");
|
String spreadsheetId = searchSpreadsheetByTitle(spreadsheetTitle, activity).getId().replace(SendDocsUtils.SPREADSHEET_ID_PREFIX, "");
|
||||||
if(spreadsheetId == null) {
|
if(spreadsheetId == null) {
|
||||||
Log.d(LOG_TAG, "Unable to find the spreadsheet -- " + spreadsheetTitle);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Unable to find the spreadsheet -- " + spreadsheetTitle);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Context context = activity.getApplicationContext();
|
Context context = activity.getApplicationContext();
|
||||||
@@ -247,7 +246,7 @@ public class GoogleUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(LOG_TAG, "Unable to fetch content of spreadsheet.", e);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Unable to fetch content of spreadsheet.", e);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -290,7 +289,7 @@ public class GoogleUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(LOG_TAG, "Unable to query fusion table.", e);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Unable to query fusion table.", e);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -320,7 +319,7 @@ public class GoogleUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d(LOG_TAG, "Failed when delete all fusion tables.", e);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Failed when delete all fusion tables.", e);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -358,7 +357,7 @@ public class GoogleUtils {
|
|||||||
response = request.execute();
|
response = request.execute();
|
||||||
return response;
|
return response;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(LOG_TAG, "Failed when send fusion table query.", e);
|
Log.d(EndToEndTestUtils.LOG_TAG, "Failed when send fusion table query.", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public class MenuItemsTest extends ActivityInstrumentationTestCase2<TrackListAct
|
|||||||
|
|
||||||
EndToEndTestUtils.SOLO.goBack();
|
EndToEndTestUtils.SOLO.goBack();
|
||||||
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_help), true);
|
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_help), true);
|
||||||
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.help_about));
|
EndToEndTestUtils.getButtonOnScreen(activityMyTracks.getString(R.string.help_about), true, true);
|
||||||
EndToEndTestUtils.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
|
EndToEndTestUtils.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
|
||||||
EndToEndTestUtils.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
|
EndToEndTestUtils.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,9 +153,11 @@ public class SettingTest extends ActivityInstrumentationTestCase2<TrackListActiv
|
|||||||
EndToEndTestUtils.createTrackIfEmpty(5, false);
|
EndToEndTestUtils.createTrackIfEmpty(5, false);
|
||||||
EndToEndTestUtils.resetAllSettings(activityMyTracks, true);
|
EndToEndTestUtils.resetAllSettings(activityMyTracks, true);
|
||||||
ChangeStatsSettings(false, false, true, true, true);
|
ChangeStatsSettings(false, false, true, true, true);
|
||||||
|
instrumentation.waitForIdleSync();
|
||||||
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.track_detail_stats_tab));
|
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.track_detail_stats_tab));
|
||||||
assertTrue(EndToEndTestUtils.SOLO.waitForText(activityMyTracks
|
assertTrue(EndToEndTestUtils.SOLO.waitForText(
|
||||||
.getString(R.string.stats_min_elevation)));
|
activityMyTracks.getString(R.string.stats_min_elevation), 1,
|
||||||
|
EndToEndTestUtils.NORMAL_WAIT_TIME, true));
|
||||||
assertTrue(EndToEndTestUtils.SOLO.waitForText(activityMyTracks
|
assertTrue(EndToEndTestUtils.SOLO.waitForText(activityMyTracks
|
||||||
.getString(R.string.stats_min_grade)));
|
.getString(R.string.stats_min_grade)));
|
||||||
assertTrue(EndToEndTestUtils.SOLO.waitForText(activityMyTracks
|
assertTrue(EndToEndTestUtils.SOLO.waitForText(activityMyTracks
|
||||||
@@ -241,10 +243,10 @@ public class SettingTest extends ActivityInstrumentationTestCase2<TrackListActiv
|
|||||||
// Write to SD card.
|
// Write to SD card.
|
||||||
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_settings), true);
|
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_settings), true);
|
||||||
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.settings_backup));
|
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.settings_backup));
|
||||||
EndToEndTestUtils.SOLO
|
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.settings_backup_now));
|
||||||
.clickOnText(activityMyTracks.getString(R.string.settings_backup_now));
|
|
||||||
assertTrue(EndToEndTestUtils.SOLO.waitForText(
|
assertTrue(EndToEndTestUtils.SOLO.waitForText(
|
||||||
activityMyTracks.getString(R.string.sd_card_save_success), 0, EndToEndTestUtils.SUPER_LONG_WAIT_TIME));
|
activityMyTracks.getString(R.string.sd_card_save_success), 0,
|
||||||
|
EndToEndTestUtils.SUPER_LONG_WAIT_TIME));
|
||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
|
|
||||||
// Delete all tracks.
|
// Delete all tracks.
|
||||||
@@ -256,11 +258,13 @@ public class SettingTest extends ActivityInstrumentationTestCase2<TrackListActiv
|
|||||||
// Read from SD card.
|
// Read from SD card.
|
||||||
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_settings), true);
|
EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_settings), true);
|
||||||
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.settings_backup));
|
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.settings_backup));
|
||||||
EndToEndTestUtils.SOLO.clickOnText(activityMyTracks
|
EndToEndTestUtils.SOLO
|
||||||
.getString(R.string.settings_backup_restore));
|
.clickOnText(activityMyTracks.getString(R.string.settings_backup_restore));
|
||||||
EndToEndTestUtils.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
|
EndToEndTestUtils
|
||||||
|
.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
|
||||||
assertTrue(EndToEndTestUtils.SOLO.waitForText(
|
assertTrue(EndToEndTestUtils.SOLO.waitForText(
|
||||||
activityMyTracks.getString(R.string.sd_card_import_success), 0, EndToEndTestUtils.NORMAL_WAIT_TIME));
|
activityMyTracks.getString(R.string.sd_card_import_success), 0,
|
||||||
|
EndToEndTestUtils.SUPER_LONG_WAIT_TIME));
|
||||||
// Check restore track.
|
// Check restore track.
|
||||||
assertTrue(EndToEndTestUtils.SOLO.searchText(EndToEndTestUtils.trackName));
|
assertTrue(EndToEndTestUtils.SOLO.searchText(EndToEndTestUtils.trackName));
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-67
@@ -10,7 +10,7 @@ import junit.framework.TestCase;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the the function of the TripStatisticsBuilder class.
|
* Test the the function of the TripStatisticsBuilder class.
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class TripStatisticsBuilderTest extends TestCase {
|
public class TripStatisticsBuilderTest extends TestCase {
|
||||||
@@ -25,55 +25,49 @@ public class TripStatisticsBuilderTest extends TestCase {
|
|||||||
|
|
||||||
public void testAddLocationSimple() throws Exception {
|
public void testAddLocationSimple() throws Exception {
|
||||||
builder = new TripStatisticsBuilder(1000);
|
builder = new TripStatisticsBuilder(1000);
|
||||||
TripStatistics stats = builder.getStatistics();
|
TripStatistics tripStatistics = builder.getTripStatistics();
|
||||||
|
|
||||||
assertEquals(0.0, builder.getSmoothedElevation());
|
assertEquals(0.0, builder.getSmoothedElevation());
|
||||||
assertEquals(Double.POSITIVE_INFINITY, stats.getMinElevation());
|
assertEquals(Double.POSITIVE_INFINITY, tripStatistics.getMinElevation());
|
||||||
assertEquals(Double.NEGATIVE_INFINITY, stats.getMaxElevation());
|
assertEquals(Double.NEGATIVE_INFINITY, tripStatistics.getMaxElevation());
|
||||||
assertEquals(0.0, stats.getMaxSpeed());
|
assertEquals(0.0, tripStatistics.getMaxSpeed());
|
||||||
assertEquals(Double.POSITIVE_INFINITY, stats.getMinGrade());
|
assertEquals(Double.POSITIVE_INFINITY, tripStatistics.getMinGrade());
|
||||||
assertEquals(Double.NEGATIVE_INFINITY, stats.getMaxGrade());
|
assertEquals(Double.NEGATIVE_INFINITY, tripStatistics.getMaxGrade());
|
||||||
assertEquals(0.0, stats.getTotalElevationGain());
|
assertEquals(0.0, tripStatistics.getTotalElevationGain());
|
||||||
assertEquals(0, stats.getMovingTime());
|
assertEquals(0, tripStatistics.getMovingTime());
|
||||||
assertEquals(0.0, stats.getTotalDistance());
|
assertEquals(0.0, tripStatistics.getTotalDistance());
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
Location l = new Location("test");
|
Location location = new Location("test");
|
||||||
l.setAccuracy(1.0f);
|
location.setAccuracy(1.0f);
|
||||||
l.setLongitude(45.0);
|
location.setLongitude(45.0);
|
||||||
|
|
||||||
// Going up by 5 meters each time.
|
// Going up by 1 meter each time.
|
||||||
l.setAltitude(i);
|
location.setAltitude(i);
|
||||||
// Moving by .1% of a degree latitude.
|
location.setLatitude(i * .001); // Moving by .001 degree latitude (111 meters)
|
||||||
l.setLatitude(i * .001);
|
location.setSpeed(11.1f);
|
||||||
l.setSpeed(11.1f);
|
|
||||||
// Each time slice is 10 seconds.
|
// Each time slice is 10 seconds.
|
||||||
long time = 1000 + 10000 * i;
|
long time = 1000 + 10000 * i;
|
||||||
l.setTime(time);
|
location.setTime(time);
|
||||||
boolean moving = builder.addLocation(l, time);
|
boolean moving = builder.addLocation(location, time);
|
||||||
assertEquals((i != 0), moving);
|
assertEquals((i != 0), moving);
|
||||||
|
|
||||||
stats = builder.getStatistics();
|
tripStatistics = builder.getTripStatistics();
|
||||||
assertEquals(10000 * i, stats.getTotalTime());
|
assertEquals(10000 * i, tripStatistics.getTotalTime());
|
||||||
assertEquals(10000 * i, stats.getMovingTime());
|
assertEquals(10000 * i, tripStatistics.getMovingTime());
|
||||||
assertEquals(i, builder.getSmoothedElevation(),
|
assertEquals(i, builder.getSmoothedElevation(), Constants.ELEVATION_SMOOTHING_FACTOR / 2);
|
||||||
Constants.ELEVATION_SMOOTHING_FACTOR / 2);
|
assertEquals(0.0, tripStatistics.getMinElevation());
|
||||||
assertEquals(0.0, stats.getMinElevation());
|
assertEquals(i, tripStatistics.getMaxElevation(), Constants.ELEVATION_SMOOTHING_FACTOR / 2);
|
||||||
assertEquals(i, stats.getMaxElevation(),
|
assertEquals(i, tripStatistics.getTotalElevationGain(), Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||||
Constants.ELEVATION_SMOOTHING_FACTOR / 2);
|
|
||||||
assertEquals(i, stats.getTotalElevationGain(),
|
|
||||||
Constants.ELEVATION_SMOOTHING_FACTOR);
|
|
||||||
|
|
||||||
if (i > Constants.SPEED_SMOOTHING_FACTOR) {
|
if (i > Constants.SPEED_SMOOTHING_FACTOR) {
|
||||||
assertEquals(11.1f, stats.getMaxSpeed(), 0.1);
|
assertEquals(11.1f, tripStatistics.getMaxSpeed(), 0.1);
|
||||||
}
|
}
|
||||||
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
|
if (i > Constants.DISTANCE_SMOOTHING_FACTOR && i > Constants.ELEVATION_SMOOTHING_FACTOR) {
|
||||||
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
|
// 1 m / 111 m = .009
|
||||||
assertEquals(0.009, stats.getMinGrade(), 0.0001);
|
assertEquals(0.009, tripStatistics.getMinGrade(), 0.0001);
|
||||||
assertEquals(0.009, stats.getMaxGrade(), 0.0001);
|
assertEquals(0.009, tripStatistics.getMaxGrade(), 0.0001);
|
||||||
}
|
}
|
||||||
// 1 degree = 111 km
|
assertEquals(111.0 * i, tripStatistics.getTotalDistance(), 100);
|
||||||
// 1 timeslice = 0.001 degree = 111 m
|
|
||||||
assertEquals(111.0 * i, stats.getTotalDistance(), 100);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +80,7 @@ public class TripStatisticsBuilderTest extends TestCase {
|
|||||||
for (int j = 0; j < 100; j++) {
|
for (int j = 0; j < 100; j++) {
|
||||||
assertEquals(0.0, builder.updateElevation(elevation));
|
assertEquals(0.0, builder.updateElevation(elevation));
|
||||||
assertEquals(elevation, builder.getSmoothedElevation());
|
assertEquals(elevation, builder.getSmoothedElevation());
|
||||||
TripStatistics data = builder.getStatistics();
|
TripStatistics data = builder.getTripStatistics();
|
||||||
assertEquals(elevation, data.getMinElevation());
|
assertEquals(elevation, data.getMinElevation());
|
||||||
assertEquals(elevation, data.getMaxElevation());
|
assertEquals(elevation, data.getMaxElevation());
|
||||||
assertEquals(0.0, data.getTotalElevationGain());
|
assertEquals(0.0, data.getTotalElevationGain());
|
||||||
@@ -104,80 +98,71 @@ public class TripStatisticsBuilderTest extends TestCase {
|
|||||||
} else {
|
} else {
|
||||||
expectedGain = 1.0;
|
expectedGain = 1.0;
|
||||||
}
|
}
|
||||||
assertEquals(expectedGain,
|
assertEquals(expectedGain, builder.updateElevation(i));
|
||||||
builder.updateElevation(i));
|
|
||||||
assertEquals(i, builder.getSmoothedElevation(), 20);
|
assertEquals(i, builder.getSmoothedElevation(), 20);
|
||||||
TripStatistics data = builder.getStatistics();
|
TripStatistics data = builder.getTripStatistics();
|
||||||
assertEquals(0.0, data.getMinElevation(), 0.0);
|
assertEquals(0.0, data.getMinElevation(), 0.0);
|
||||||
assertEquals(i, data.getMaxElevation(),
|
assertEquals(i, data.getMaxElevation(), Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||||
Constants.ELEVATION_SMOOTHING_FACTOR);
|
assertEquals(i, data.getTotalElevationGain(), Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||||
assertEquals(i, data.getTotalElevationGain(),
|
|
||||||
Constants.ELEVATION_SMOOTHING_FACTOR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGradeSimple() throws Exception {
|
public void testGradeSimple() throws Exception {
|
||||||
for (double i = 0; i < 1000; i++) {
|
for (double i = 0; i < 1000; i++) {
|
||||||
// The value of the elevation does not matter. This is just to fill the
|
// The value of the elevation does not matter. This is just to fill the
|
||||||
// buffer.
|
// buffer.
|
||||||
builder.updateElevation(i);
|
builder.updateElevation(i);
|
||||||
builder.updateGrade(100, 100);
|
builder.updateGrade(100, 100);
|
||||||
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
|
if ((i > Constants.GRADE_SMOOTHING_FACTOR) && (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
|
||||||
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
|
assertEquals(1.0, builder.getTripStatistics().getMaxGrade());
|
||||||
assertEquals(1.0, builder.getStatistics().getMaxGrade());
|
assertEquals(1.0, builder.getTripStatistics().getMinGrade());
|
||||||
assertEquals(1.0, builder.getStatistics().getMinGrade());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (double i = 0; i < 1000; i++) {
|
for (double i = 0; i < 1000; i++) {
|
||||||
// The value of the elevation does not matter. This is just to fill the
|
// The value of the elevation does not matter. This is just to fill the
|
||||||
// buffer.
|
// buffer.
|
||||||
builder.updateElevation(i);
|
builder.updateElevation(i);
|
||||||
builder.updateGrade(100, -100);
|
builder.updateGrade(100, -100);
|
||||||
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
|
if ((i > Constants.GRADE_SMOOTHING_FACTOR) && (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
|
||||||
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
|
assertEquals(1.0, builder.getTripStatistics().getMaxGrade());
|
||||||
assertEquals(1.0, builder.getStatistics().getMaxGrade());
|
assertEquals(-1.0, builder.getTripStatistics().getMinGrade());
|
||||||
assertEquals(-1.0, builder.getStatistics().getMinGrade());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGradeIgnoreShort() throws Exception {
|
public void testGradeIgnoreShort() throws Exception {
|
||||||
for (double i = 0; i < 100; i++) {
|
for (double i = 0; i < 100; i++) {
|
||||||
// The value of the elevation does not matter. This is just to fill the
|
// The value of the elevation does not matter. This is just to fill the
|
||||||
// buffer.
|
// buffer.
|
||||||
builder.updateElevation(i);
|
builder.updateElevation(i);
|
||||||
builder.updateGrade(1, 100);
|
builder.updateGrade(1, 100);
|
||||||
assertEquals(Double.NEGATIVE_INFINITY, builder.getStatistics().getMaxGrade());
|
assertEquals(Double.NEGATIVE_INFINITY, builder.getTripStatistics().getMaxGrade());
|
||||||
assertEquals(Double.POSITIVE_INFINITY, builder.getStatistics().getMinGrade());
|
assertEquals(Double.POSITIVE_INFINITY, builder.getTripStatistics().getMinGrade());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUpdateSpeedIncludeZero() {
|
public void testUpdateSpeedIncludeZero() {
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
builder.updateSpeed(i + 1000, 0.0, i, 4.0);
|
builder.updateSpeed(i + 1000, 0.0, i, 4.0);
|
||||||
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
|
assertEquals(0.0, builder.getTripStatistics().getMaxSpeed());
|
||||||
assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUpdateSpeedIngoreErrorCode() {
|
public void testUpdateSpeedIngoreErrorCode() {
|
||||||
builder.updateSpeed(12345000, 128.0, 12344000, 0.0);
|
builder.updateSpeed(12345000, 128.0, 12344000, 0.0);
|
||||||
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
|
assertEquals(0.0, builder.getTripStatistics().getMaxSpeed());
|
||||||
assertEquals(1000, builder.getStatistics().getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUpdateSpeedIngoreLargeAcceleration() {
|
public void testUpdateSpeedIngoreLargeAcceleration() {
|
||||||
builder.updateSpeed(12345000, 100.0, 12344000, 1.0);
|
builder.updateSpeed(12345000, 100.0, 12344000, 1.0);
|
||||||
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
|
assertEquals(0.0, builder.getTripStatistics().getMaxSpeed());
|
||||||
assertEquals(1000, builder.getStatistics().getMovingTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUpdateSpeed() {
|
public void testUpdateSpeed() {
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
builder.updateSpeed(i + 1000, 4.0, i, 4.0);
|
builder.updateSpeed(i + 1000, 4.0, i, 4.0);
|
||||||
assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime());
|
|
||||||
if (i > Constants.SPEED_SMOOTHING_FACTOR) {
|
if (i > Constants.SPEED_SMOOTHING_FACTOR) {
|
||||||
assertEquals(4.0, builder.getStatistics().getMaxSpeed());
|
assertEquals(4.0, builder.getTripStatistics().getMaxSpeed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user