forked from upstream-mirrors/OpenTracks
Merge heads
This commit is contained in:
@@ -142,5 +142,12 @@ limitations under the License.
|
|||||||
<include
|
<include
|
||||||
android:id="@+id/stats_calorie"
|
android:id="@+id/stats_calorie"
|
||||||
layout="@layout/stats_small_item" />
|
layout="@layout/stats_small_item" />
|
||||||
|
<!-- Setup activity type-->
|
||||||
|
<Button
|
||||||
|
android:id="@+id/stats_calorie_setup"
|
||||||
|
android:layout_gravity="right"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:text="@string/stats_calorie_setup" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</merge>
|
</merge>
|
||||||
@@ -2141,6 +2141,12 @@ limitations under the License.
|
|||||||
Character limit: ~23 (1 line)">
|
Character limit: ~23 (1 line)">
|
||||||
Calories
|
Calories
|
||||||
</string>
|
</string>
|
||||||
|
<string name="stats_calorie_setup"
|
||||||
|
translation_description="In the 'Stats' page, the button to setup calorie.
|
||||||
|
|
||||||
|
Character limit: ~23 (1 line)">
|
||||||
|
Setup Activity Type
|
||||||
|
</string>
|
||||||
<string name="stats_fastest_pace"
|
<string name="stats_fastest_pace"
|
||||||
translation_description="In the 'Stats' page, the fastest pace.">
|
translation_description="In the 'Stats' page, the fastest pace.">
|
||||||
Fastest pace
|
Fastest pace
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.google.android.apps.mytracks;
|
|||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.apps.mytracks.util.StatsUtils;
|
import com.google.android.apps.mytracks.util.StatsUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
@@ -36,7 +37,8 @@ public class AggregatedStatsActivity extends AbstractMyTracksActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
StatsUtils.setTripStatisticsValues(this, getTripStatistics());
|
StatsUtils.setTripStatisticsValues(this, getTripStatistics(),
|
||||||
|
PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
||||||
StatsUtils.setLocationValues(this, null, false);
|
StatsUtils.setLocationValues(this, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.google.android.apps.mytracks.content.Track;
|
|||||||
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment;
|
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment;
|
||||||
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller;
|
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller;
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackNameUtils;
|
import com.google.android.apps.mytracks.util.TrackNameUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -180,6 +181,12 @@ public class TrackEditActivity extends AbstractMyTracksActivity
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
track.setName(name.getText().toString());
|
track.setName(name.getText().toString());
|
||||||
String category = activityType.getText().toString();
|
String category = activityType.getText().toString();
|
||||||
|
if (!category.equals(track.getCategory())) {
|
||||||
|
// TODO Is there no race condition when setCalorie is called.
|
||||||
|
double calorie = CalorieUtils.calculateTrackCalorie(getApplicationContext(), track,
|
||||||
|
category);
|
||||||
|
track.getTripStatistics().setCalorie(calorie);
|
||||||
|
}
|
||||||
track.setCategory(category);
|
track.setCategory(category);
|
||||||
track.setIcon(TrackIconUtils.getIconValue(TrackEditActivity.this, category));
|
track.setIcon(TrackIconUtils.getIconValue(TrackEditActivity.this, category));
|
||||||
track.setDescription(description.getText().toString());
|
track.setDescription(description.getText().toString());
|
||||||
|
|||||||
@@ -587,8 +587,7 @@ public class TrackDataHub implements DataSourceListener {
|
|||||||
*
|
*
|
||||||
* @return the selectedTrackId
|
* @return the selectedTrackId
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
public long getSelectedTrackId() {
|
||||||
long getSelectedTrackId() {
|
|
||||||
return selectedTrackId;
|
return selectedTrackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.google.android.apps.mytracks.content.Waypoint;
|
|||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||||
import com.google.android.apps.mytracks.util.PhotoUtils;
|
import com.google.android.apps.mytracks.util.PhotoUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.apps.mytracks.util.StatsUtils;
|
import com.google.android.apps.mytracks.util.StatsUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
@@ -192,7 +193,8 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
TextView name = (TextView) getView().findViewById(R.id.marker_detail_statistics_name);
|
TextView name = (TextView) getView().findViewById(R.id.marker_detail_statistics_name);
|
||||||
name.setText(getString(R.string.generic_name_line, waypoint.getName()));
|
name.setText(getString(R.string.generic_name_line, waypoint.getName()));
|
||||||
|
|
||||||
StatsUtils.setTripStatisticsValues(getActivity(), waypoint.getTripStatistics());
|
StatsUtils.setTripStatisticsValues(getActivity(), waypoint.getTripStatistics(),
|
||||||
|
PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
||||||
StatsUtils.setLocationValues(getActivity(), waypoint.getLocation(), false);
|
StatsUtils.setLocationValues(getActivity(), waypoint.getLocation(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,7 +259,11 @@ public class StatsFragment extends Fragment implements TrackDataListener {
|
|||||||
* Updates the UI.
|
* Updates the UI.
|
||||||
*/
|
*/
|
||||||
private void updateUi(FragmentActivity activity) {
|
private void updateUi(FragmentActivity activity) {
|
||||||
StatsUtils.setTripStatisticsValues(activity, lastTripStatistics);
|
StatsUtils.setTripStatisticsValues(
|
||||||
|
activity,
|
||||||
|
lastTripStatistics,
|
||||||
|
trackDataHub == null ? PreferencesUtils.RECORDING_TRACK_ID_DEFAULT : trackDataHub
|
||||||
|
.getSelectedTrackId());
|
||||||
StatsUtils.setLocationValues(activity, lastLocation, isSelectedTrackRecording());
|
StatsUtils.setLocationValues(activity, lastLocation, isSelectedTrackRecording());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-8
@@ -242,11 +242,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
trackTripStatisticstrackUpdater.addLocation(trackPoint, recordingDistanceInterval,
|
trackTripStatisticstrackUpdater.addLocation(trackPoint, recordingDistanceInterval,
|
||||||
PreferencesUtils.getInt(context, R.string.stats_weight_key,
|
context);
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
markerTripStatisticsUpdater.addLocation(trackPoint, recordingDistanceInterval, context);
|
||||||
markerTripStatisticsUpdater.addLocation(trackPoint, recordingDistanceInterval,
|
|
||||||
PreferencesUtils.getInt(context, R.string.stats_weight_key,
|
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
|
||||||
}
|
}
|
||||||
if (waypoint.getLocation().getTime() > trackPoint.getTime()) {
|
if (waypoint.getLocation().getTime() > trackPoint.getTime()) {
|
||||||
trackPoint = null;
|
trackPoint = null;
|
||||||
@@ -549,9 +546,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
trackData.tripStatisticsUpdater = new TripStatisticsUpdater(
|
trackData.tripStatisticsUpdater = new TripStatisticsUpdater(
|
||||||
location.getTime() != -1L ? location.getTime() : trackData.importTime);
|
location.getTime() != -1L ? location.getTime() : trackData.importTime);
|
||||||
}
|
}
|
||||||
trackData.tripStatisticsUpdater.addLocation(location, recordingDistanceInterval,
|
trackData.tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context);
|
||||||
PreferencesUtils.getInt(context, R.string.stats_weight_key,
|
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
|
||||||
|
|
||||||
trackData.bufferedLocations[trackData.numBufferedLocations] = location;
|
trackData.bufferedLocations[trackData.numBufferedLocations] = location;
|
||||||
trackData.numBufferedLocations++;
|
trackData.numBufferedLocations++;
|
||||||
|
|||||||
@@ -277,8 +277,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
|
|||||||
sentStartMarker = true;
|
sentStartMarker = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, PreferencesUtils
|
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context);
|
||||||
.getInt(context, R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
|
||||||
if (i % elevationSamplingFrequency == 0) {
|
if (i % elevationSamplingFrequency == 0) {
|
||||||
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
|
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
|
||||||
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
|
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
|
||||||
|
|||||||
@@ -659,13 +659,9 @@ public class TrackRecordingService extends Service {
|
|||||||
if (cursor.moveToLast()) {
|
if (cursor.moveToLast()) {
|
||||||
do {
|
do {
|
||||||
Location location = myTracksProviderUtils.createTrackPoint(cursor);
|
Location location = myTracksProviderUtils.createTrackPoint(cursor);
|
||||||
trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval,
|
trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context);
|
||||||
PreferencesUtils.getInt(context, R.string.stats_weight_key,
|
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
|
||||||
if (location.getTime() > markerStartTime) {
|
if (location.getTime() > markerStartTime) {
|
||||||
markerTripStatisticsUpdater.addLocation(location, recordingDistanceInterval,
|
markerTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context);
|
||||||
PreferencesUtils.getInt(context, R.string.stats_weight_key,
|
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
|
||||||
}
|
}
|
||||||
} while (cursor.moveToPrevious());
|
} while (cursor.moveToPrevious());
|
||||||
}
|
}
|
||||||
@@ -1005,10 +1001,8 @@ public class TrackRecordingService extends Service {
|
|||||||
try {
|
try {
|
||||||
Uri uri = myTracksProviderUtils.insertTrackPoint(location, track.getId());
|
Uri uri = myTracksProviderUtils.insertTrackPoint(location, track.getId());
|
||||||
long trackPointId = Long.parseLong(uri.getLastPathSegment());
|
long trackPointId = Long.parseLong(uri.getLastPathSegment());
|
||||||
trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, PreferencesUtils
|
trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context);
|
||||||
.getInt(context, R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
markerTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context);
|
||||||
markerTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, PreferencesUtils
|
|
||||||
.getInt(context, R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
|
||||||
updateRecordingTrack(track, trackPointId, LocationUtils.isValidLocation(location));
|
updateRecordingTrack(track, trackPointId, LocationUtils.isValidLocation(location));
|
||||||
} catch (SQLiteException e) {
|
} catch (SQLiteException e) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public class StatsSettingsActivity extends AbstractSettingsActivity {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
ListPreference listPreference = (ListPreference) findPreference(getString(R.string.stats_units_key));
|
ListPreference listPreference = (ListPreference) findPreference(getString(R.string.stats_units_key));
|
||||||
OnPreferenceChangeListener listener = new OnPreferenceChangeListener() {
|
OnPreferenceChangeListener listener = new OnPreferenceChangeListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference pref, Object newValue) {
|
public boolean onPreferenceChange(Preference pref, Object newValue) {
|
||||||
configRateListPreference(PreferencesUtils.STATS_UNITS_DEFAULT.equals((String) newValue));
|
configRateListPreference(PreferencesUtils.STATS_UNITS_DEFAULT.equals((String) newValue));
|
||||||
@@ -83,6 +84,10 @@ public class StatsSettingsActivity extends AbstractSettingsActivity {
|
|||||||
* activity.
|
* activity.
|
||||||
*/
|
*/
|
||||||
updateWeightSummary(PreferencesUtils.STATS_UNITS_DEFAULT.equals((String) newValue));
|
updateWeightSummary(PreferencesUtils.STATS_UNITS_DEFAULT.equals((String) newValue));
|
||||||
|
// Recreate weight value dialog.
|
||||||
|
removeDialog(WEIGHT_INPUT_DIALOG);
|
||||||
|
onCreateDialog(WEIGHT_INPUT_DIALOG);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -134,7 +139,8 @@ public class StatsSettingsActivity extends AbstractSettingsActivity {
|
|||||||
case WEIGHT_INPUT_DIALOG:
|
case WEIGHT_INPUT_DIALOG:
|
||||||
final EditText weightInput = new EditText(this);
|
final EditText weightInput = new EditText(this);
|
||||||
weightInput.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
|
weightInput.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
|
||||||
weightInput.setText(Integer.toString(PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
weightInput.setText(Integer.toString(getWeightDisplayValue(PreferencesUtils
|
||||||
|
.isMetricUnits(getApplicationContext()))));
|
||||||
weightInput.setSelectAllOnFocus(true);
|
weightInput.setSelectAllOnFocus(true);
|
||||||
dialog = (new AlertDialog.Builder(this))
|
dialog = (new AlertDialog.Builder(this))
|
||||||
.setMessage(R.string.settings_stats_calorie_weight_description)
|
.setMessage(R.string.settings_stats_calorie_weight_description)
|
||||||
|
|||||||
@@ -22,8 +22,11 @@ import static com.google.android.apps.mytracks.services.TrackRecordingService.PA
|
|||||||
import com.google.android.apps.mytracks.util.CalorieUtils;
|
import com.google.android.apps.mytracks.util.CalorieUtils;
|
||||||
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -120,13 +123,34 @@ public class TripStatisticsUpdater {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a location.
|
||||||
|
*
|
||||||
|
* @param location the location
|
||||||
|
* @param minRecordingDistance the min recording distance
|
||||||
|
* @param context the context to get the weight and track category
|
||||||
|
*/
|
||||||
|
public void addLocation(Location location, int minRecordingDistance, Context context) {
|
||||||
|
int weight = PreferencesUtils.getInt(context, R.string.stats_weight_key,
|
||||||
|
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
||||||
|
addLocation(
|
||||||
|
location,
|
||||||
|
minRecordingDistance,
|
||||||
|
CalorieUtils.getActivityType(context,
|
||||||
|
PreferencesUtils.getLong(context, R.string.recording_track_id_key)), weight);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a location. TODO: This assume location has a valid time.
|
* Adds a location. TODO: This assume location has a valid time.
|
||||||
*
|
*
|
||||||
* @param location the location
|
* @param location the location
|
||||||
* @param minRecordingDistance the min recording distance
|
* @param minRecordingDistance the min recording distance
|
||||||
|
* @param activityType the activity type of current track
|
||||||
|
* @param weight the weight to calculate calorie
|
||||||
*/
|
*/
|
||||||
public void addLocation(Location location, int minRecordingDistance, int weight) {
|
@VisibleForTesting
|
||||||
|
void addLocation(Location location, int minRecordingDistance, ActivityType activityType,
|
||||||
|
int weight) {
|
||||||
// Always update time
|
// Always update time
|
||||||
updateTime(location.getTime());
|
updateTime(location.getTime());
|
||||||
|
|
||||||
@@ -191,12 +215,9 @@ public class TripStatisticsUpdater {
|
|||||||
location.getTime(), location.getSpeed(), lastLocation.getTime(), lastLocation.getSpeed());
|
location.getTime(), location.getSpeed(), lastLocation.getTime(), lastLocation.getSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 1: How to get the value of weight.
|
|
||||||
// TODO 2: How to get the value of ActivityType.
|
|
||||||
|
|
||||||
// Update calorie
|
// Update calorie
|
||||||
double calorie = CalorieUtils.getCalorie(lastMovingLocation, location,
|
double calorie = CalorieUtils.getCalorie(lastMovingLocation, location,
|
||||||
gradeBuffer.getAverage(), weight, ActivityType.FOOT);
|
gradeBuffer.getAverage(), weight, activityType);
|
||||||
currentSegment.addCalorie(calorie);
|
currentSegment.addCalorie(calorie);
|
||||||
|
|
||||||
lastLocation = location;
|
lastLocation = location;
|
||||||
|
|||||||
@@ -15,8 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,7 +70,7 @@ public class CalorieUtils {
|
|||||||
* UnitConversions.KM_TO_M / UnitConversions.HR_TO_MIN;
|
* UnitConversions.KM_TO_M / UnitConversions.HR_TO_MIN;
|
||||||
|
|
||||||
public enum ActivityType {
|
public enum ActivityType {
|
||||||
CYCLING, FOOT
|
CYCLING, FOOT, INVALID
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,14 +134,14 @@ public class CalorieUtils {
|
|||||||
* @param grade the grade to calculate
|
* @param grade the grade to calculate
|
||||||
* @param weight of rider plus bike, in kilogram
|
* @param weight of rider plus bike, in kilogram
|
||||||
* @param timeUsed how many times used in second
|
* @param timeUsed how many times used in second
|
||||||
* @return the power value watts(Joule/second).
|
* @return the calorie value in kcal.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static double calculateCyclingCalorie(double speed, double grade, int weight, double timeUsed) {
|
static double calculateCyclingCalorie(double speed, double grade, int weight, double timeUsed) {
|
||||||
// Get the Power, the unit is Watt (Joule/second)
|
// Get the Power, the unit is Watt (Joule/second)
|
||||||
double power = earthGravity * weight * speed * (K1 + grade) + K2 * (speed * speed * speed);
|
double power = earthGravity * weight * speed * (K1 + grade) + K2 * (speed * speed * speed);
|
||||||
|
|
||||||
// Get the calories
|
// Get the calories in kcal
|
||||||
return power * timeUsed / UnitConversions.KCAL_TO_J;
|
return power * timeUsed / UnitConversions.KCAL_TO_J;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +219,88 @@ public class CalorieUtils {
|
|||||||
*/
|
*/
|
||||||
public static double getCalorie(Location start, Location stop, double grade, int weight,
|
public static double getCalorie(Location start, Location stop, double grade, int weight,
|
||||||
ActivityType activityType) {
|
ActivityType activityType) {
|
||||||
|
if (activityType == ActivityType.INVALID) {
|
||||||
|
return TripStatistics.CALORIE_UNDEFINED;
|
||||||
|
}
|
||||||
return ActivityType.CYCLING == activityType ? calculateCalorieCycling(start, stop, grade,
|
return ActivityType.CYCLING == activityType ? calculateCalorieCycling(start, stop, grade,
|
||||||
weight) : calculateCalorieFoot(start, stop, grade, weight);
|
weight) : calculateCalorieFoot(start, stop, grade, weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the activity type for calculating calorie by the id of track.
|
||||||
|
*
|
||||||
|
* @param context current context
|
||||||
|
* @param trackId the id of track
|
||||||
|
* @return activityType the activity type of track.
|
||||||
|
*/
|
||||||
|
public static ActivityType getActivityType(Context context, long trackId) {
|
||||||
|
ActivityType activityType = ActivityType.INVALID;
|
||||||
|
|
||||||
|
Track track = MyTracksProviderUtils.Factory.get(context).getTrack(trackId);
|
||||||
|
if (track != null) {
|
||||||
|
String category = track.getCategory();
|
||||||
|
|
||||||
|
if (category.equals(context.getString(R.string.activity_type_walking))
|
||||||
|
|| category.equals(context.getString(R.string.activity_type_running))) {
|
||||||
|
activityType = ActivityType.FOOT;
|
||||||
|
} else if (category.equals(context.getString(R.string.activity_type_cycling))
|
||||||
|
|| category.equals(context.getString(R.string.activity_type_biking))) {
|
||||||
|
activityType = ActivityType.CYCLING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return activityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the activity type for calculating calorie by the category of track.
|
||||||
|
*
|
||||||
|
* @param context current context
|
||||||
|
* @param category the category of track
|
||||||
|
* @return activityType the activity type of track.
|
||||||
|
*/
|
||||||
|
private static ActivityType getActivityType(Context context, String category) {
|
||||||
|
ActivityType activityType = ActivityType.INVALID;
|
||||||
|
if (category.equals(context.getString(R.string.activity_type_walking))
|
||||||
|
|| category.equals(context.getString(R.string.activity_type_running))) {
|
||||||
|
activityType = ActivityType.FOOT;
|
||||||
|
} else if (category.equals(context.getString(R.string.activity_type_cycling))
|
||||||
|
|| category.equals(context.getString(R.string.activity_type_biking))) {
|
||||||
|
activityType = ActivityType.CYCLING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return activityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the calorie of track.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param track the track to calculate
|
||||||
|
* @param category the category of track
|
||||||
|
*/
|
||||||
|
public static double calculateTrackCalorie(Context context, Track track, String category) {
|
||||||
|
ActivityType activityType = getActivityType(context, category);
|
||||||
|
if (activityType == ActivityType.INVALID) {
|
||||||
|
return TripStatistics.CALORIE_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
double calorie = 0.0;
|
||||||
|
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||||
|
long trackId = track.getId();
|
||||||
|
LocationIterator points = providerUtils.getTrackPointLocationIterator(trackId, -1, false,
|
||||||
|
MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||||
|
// TODO How get grade
|
||||||
|
double grade = 0;
|
||||||
|
if (points.hasNext()) {
|
||||||
|
Location start = points.next();
|
||||||
|
while (points.hasNext()) {
|
||||||
|
Location stop = points.next();
|
||||||
|
calorie += getCalorie(start, stop, grade, PreferencesUtils.getInt(context,
|
||||||
|
R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT), activityType);
|
||||||
|
start = stop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return calorie;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,12 +16,16 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.TrackEditActivity;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -108,8 +112,9 @@ public class StatsUtils {
|
|||||||
*
|
*
|
||||||
* @param activity the activity
|
* @param activity the activity
|
||||||
* @param tripStatistics the trip statistics
|
* @param tripStatistics the trip statistics
|
||||||
|
* @param trackId the id of track
|
||||||
*/
|
*/
|
||||||
public static void setTripStatisticsValues(Activity activity, TripStatistics tripStatistics) {
|
public static void setTripStatisticsValues(Activity activity, TripStatistics tripStatistics, long trackId) {
|
||||||
boolean metricUnits = PreferencesUtils.isMetricUnits(activity);
|
boolean metricUnits = PreferencesUtils.isMetricUnits(activity);
|
||||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(activity);
|
boolean reportSpeed = PreferencesUtils.isReportSpeed(activity);
|
||||||
|
|
||||||
@@ -183,8 +188,11 @@ public class StatsUtils {
|
|||||||
if (showCalorie) {
|
if (showCalorie) {
|
||||||
calorieHorizontalLine.setVisibility(View.VISIBLE);
|
calorieHorizontalLine.setVisibility(View.VISIBLE);
|
||||||
calorieContainer.setVisibility(View.VISIBLE);
|
calorieContainer.setVisibility(View.VISIBLE);
|
||||||
double calories = tripStatistics == null ? Double.NaN : tripStatistics.getCalorie();
|
double calories = Double.NaN;
|
||||||
setCalorie(activity, R.id.stats_calorie, R.string.stats_calorie, calories);
|
if (tripStatistics != null) {
|
||||||
|
calories = tripStatistics.getCalorie();
|
||||||
|
}
|
||||||
|
setCalorie(activity, R.id.stats_calorie, calories, trackId);
|
||||||
} else {
|
} else {
|
||||||
calorieHorizontalLine.setVisibility(View.GONE);
|
calorieHorizontalLine.setVisibility(View.GONE);
|
||||||
calorieContainer.setVisibility(View.GONE);
|
calorieContainer.setVisibility(View.GONE);
|
||||||
@@ -336,11 +344,42 @@ public class StatsUtils {
|
|||||||
*
|
*
|
||||||
* @param activity the activity
|
* @param activity the activity
|
||||||
* @param itemId the item id
|
* @param itemId the item id
|
||||||
* @param labelId the calorie label id
|
|
||||||
* @param calorie the value of calorie
|
* @param calorie the value of calorie
|
||||||
|
* @param trackId the id of track which is used to start track edit activity
|
||||||
|
* when user want to change the activity type
|
||||||
*/
|
*/
|
||||||
private static void setCalorie(Activity activity, int itemId, int labelId, double calorie) {
|
private static void setCalorie(final Activity activity, int itemId, double calorie,
|
||||||
setItem(activity, itemId, labelId,
|
final long trackId) {
|
||||||
String.format(Locale.getDefault(), CALORIES_FORMAT, calorie), activity.getString(R.string.unit_calorie));
|
String calorieString;
|
||||||
|
View view = activity.findViewById(itemId);
|
||||||
|
Button button = (Button) activity.findViewById(R.id.stats_calorie_setup);
|
||||||
|
// Current activity type is not supported.
|
||||||
|
if (calorie == TripStatistics.CALORIE_UNDEFINED) {
|
||||||
|
button.setVisibility(View.VISIBLE);
|
||||||
|
view.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return when it is not a valid track, which may be aggregated stats or
|
||||||
|
* marker.
|
||||||
|
*/
|
||||||
|
if (trackId == PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
||||||
|
button.setVisibility(View.GONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
button.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent intent = IntentUtils.newIntent(activity, TrackEditActivity.class).putExtra(
|
||||||
|
TrackEditActivity.EXTRA_TRACK_ID, trackId);
|
||||||
|
activity.startActivity(intent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
button.setVisibility(View.GONE);
|
||||||
|
view.setVisibility(View.VISIBLE);
|
||||||
|
calorieString = String.format(Locale.getDefault(), CALORIES_FORMAT, calorie);
|
||||||
|
setItem(activity, itemId, R.string.stats_calorie, calorieString,
|
||||||
|
activity.getString(R.string.unit_calorie));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,5 +78,8 @@ public class UnitConversions {
|
|||||||
public static final double DEG_TO_RAD = Math.PI / 180.0;
|
public static final double DEG_TO_RAD = Math.PI / 180.0;
|
||||||
|
|
||||||
// multiplication factor to convert Kcal to joules.
|
// multiplication factor to convert Kcal to joules.
|
||||||
public static final double KCAL_TO_J = 4.184;
|
public static final double KCAL_TO_J = 4184;
|
||||||
|
|
||||||
|
// multiplication factor to convert joules to Kcal.
|
||||||
|
public static final double J_TO_KCAL = 1 / KCAL_TO_J;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,8 +62,14 @@ public class TripStatistics implements Parcelable {
|
|||||||
// The min and max grade seen on this trip.
|
// The min and max grade seen on this trip.
|
||||||
private final ExtremityMonitor gradeExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor gradeExtremities = new ExtremityMonitor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value means the calorie value is invalid due to activity type is not
|
||||||
|
* supported.
|
||||||
|
*/
|
||||||
|
public static final double CALORIE_UNDEFINED = -1.0;
|
||||||
|
|
||||||
// The calorie of current track.
|
// The calorie of current track.
|
||||||
private double calorie;
|
private double calorie = CALORIE_UNDEFINED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
@@ -122,7 +128,9 @@ public class TripStatistics implements Parcelable {
|
|||||||
gradeExtremities.update(other.gradeExtremities.getMin());
|
gradeExtremities.update(other.gradeExtremities.getMin());
|
||||||
gradeExtremities.update(other.gradeExtremities.getMax());
|
gradeExtremities.update(other.gradeExtremities.getMax());
|
||||||
}
|
}
|
||||||
calorie += other.calorie;
|
if (other.calorie != CALORIE_UNDEFINED) {
|
||||||
|
calorie += other.calorie;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -532,7 +540,6 @@ public class TripStatistics implements Parcelable {
|
|||||||
data.gradeExtremities.set(minGrade, maxGrade);
|
data.gradeExtremities.set(minGrade, maxGrade);
|
||||||
|
|
||||||
data.calorie = source.readDouble();
|
data.calorie = source.readDouble();
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,7 +585,11 @@ public class TripStatistics implements Parcelable {
|
|||||||
* @param calorieAdded add the value to the total calorie
|
* @param calorieAdded add the value to the total calorie
|
||||||
*/
|
*/
|
||||||
public void addCalorie(double calorieAdded) {
|
public void addCalorie(double calorieAdded) {
|
||||||
this.calorie += calorieAdded;
|
if (calorieAdded != CALORIE_UNDEFINED) {
|
||||||
|
calorie = calorie == CALORIE_UNDEFINED ? calorieAdded : calorie + calorieAdded;
|
||||||
|
} else {
|
||||||
|
calorie = CALORIE_UNDEFINED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -591,7 +602,7 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets calories value.
|
* Gets calorie value.
|
||||||
*/
|
*/
|
||||||
public double getCalorie() {
|
public double getCalorie() {
|
||||||
return calorie;
|
return calorie;
|
||||||
|
|||||||
+4
-3
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.stats;
|
package com.google.android.apps.mytracks.stats;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
@@ -224,7 +225,7 @@ public class TripStatisticsUpdaterTest extends TestCase {
|
|||||||
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, MOVING_SPEED,
|
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, MOVING_SPEED,
|
||||||
startTime + (timeOffset + i) * TEN_SECONDS);
|
startTime + (timeOffset + i) * TEN_SECONDS);
|
||||||
tripStatisticsUpdater.addLocation(location,
|
tripStatisticsUpdater.addLocation(location,
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT,
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, ActivityType.FOOT,
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
||||||
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
||||||
|
|
||||||
@@ -271,7 +272,7 @@ public class TripStatisticsUpdaterTest extends TestCase {
|
|||||||
Location location = getLocation(
|
Location location = getLocation(
|
||||||
locationOffset, locationOffset * .001, 0, startTime + (i + timeOffset) * TEN_SECONDS);
|
locationOffset, locationOffset * .001, 0, startTime + (i + timeOffset) * TEN_SECONDS);
|
||||||
tripStatisticsUpdater.addLocation(location,
|
tripStatisticsUpdater.addLocation(location,
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT,
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, ActivityType.FOOT,
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
||||||
|
|
||||||
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
||||||
@@ -309,7 +310,7 @@ public class TripStatisticsUpdaterTest extends TestCase {
|
|||||||
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, 99999,
|
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, 99999,
|
||||||
startTime + (timeOffset + i) * TEN_SECONDS);
|
startTime + (timeOffset + i) * TEN_SECONDS);
|
||||||
tripStatisticsUpdater.addLocation(location,
|
tripStatisticsUpdater.addLocation(location,
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT,
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, ActivityType.FOOT,
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
||||||
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ public class CalorieUtilsTest extends TestCase {
|
|||||||
|
|
||||||
Location start = new Location(LocationManager.GPS_PROVIDER);
|
Location start = new Location(LocationManager.GPS_PROVIDER);
|
||||||
Location stop = new Location(LocationManager.GPS_PROVIDER);
|
Location stop = new Location(LocationManager.GPS_PROVIDER);
|
||||||
private double grade = 10.0;
|
private double grade = 0.07;
|
||||||
private int weight = 20;
|
private int weight = 80;
|
||||||
private final long TIME_INTERVAL = 1000l;
|
private final long TIME_INTERVAL = 1000l;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,4 +94,16 @@ public class CalorieUtilsTest extends TestCase {
|
|||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks calculating cycling calorie.
|
||||||
|
*/
|
||||||
|
public void testCalculateCalorieCycling() {
|
||||||
|
grade = 0;
|
||||||
|
weight = 90;
|
||||||
|
start.setSpeed(9);
|
||||||
|
stop.setSpeed(9);
|
||||||
|
double expected = 175 / 1000 / UnitConversions.KCAL_TO_J;
|
||||||
|
double actual = CalorieUtils.calculateCalorieCycling(start, stop, grade, weight);
|
||||||
|
assertEquals(expected, actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user