forked from upstream-mirrors/OpenTracks
merge heads
This commit is contained in:
@@ -18,11 +18,13 @@ 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.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsUpdater;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
|
||||
/**
|
||||
@@ -36,7 +38,7 @@ public class CalorieUtils {
|
||||
* Activity types.
|
||||
*/
|
||||
public enum ActivityType {
|
||||
CYCLING, FOOT, INVALID
|
||||
CYCLING, RUNNING, WALKING, INVALID
|
||||
}
|
||||
|
||||
private CalorieUtils() {}
|
||||
@@ -47,15 +49,10 @@ public class CalorieUtils {
|
||||
*/
|
||||
private static final double RESTING_VO2 = 3.5;
|
||||
|
||||
/**
|
||||
* Ratio to convert liter to kcal.
|
||||
*/
|
||||
private static final double L_TO_KCAL = 5.0;
|
||||
|
||||
/**
|
||||
* Standard gravity in meters per second squared (m/s^2).
|
||||
*/
|
||||
private static final double EARTH_GRAVITY = 9.80665;
|
||||
private static final double EARTH_GRAVITY = 9.81;
|
||||
|
||||
/**
|
||||
* Lumped constant for all frictional losses (tires, bearings, chain).
|
||||
@@ -63,22 +60,10 @@ public class CalorieUtils {
|
||||
private static final double K1 = 0.0053;
|
||||
|
||||
/**
|
||||
* Lumped constant for aerodynamic drag.
|
||||
* Lumped constant for aerodynamic drag (kg/m)
|
||||
*/
|
||||
private static final double K2 = 0.185;
|
||||
|
||||
/**
|
||||
* Critical speed running in meters per minute. Converts 4.5 miles per hour to
|
||||
* meters per minute. 4 miles per hour is regarded as the max speed of walking
|
||||
* and 5 miles per hour is regarded as the minimal speed of running, so we use
|
||||
* 4.5 miles per hour as the critical speed. <a href=
|
||||
* "http://www.ideafit.com/fitness-library/calculating-caloric-expenditure-0"
|
||||
* >Reference</a>
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static final double CRTICAL_SPEED_RUNNING = 4.5 * UnitConversions.MI_TO_KM
|
||||
* UnitConversions.KM_TO_M / UnitConversions.HR_TO_MIN;
|
||||
|
||||
/**
|
||||
* Gets the activity type.
|
||||
*
|
||||
@@ -86,9 +71,13 @@ public class CalorieUtils {
|
||||
* @param activityType the activity type
|
||||
*/
|
||||
public static ActivityType getActivityType(Context context, String activityType) {
|
||||
if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.WALK)
|
||||
|| TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.RUN)) {
|
||||
return ActivityType.FOOT;
|
||||
if (activityType == null || activityType.equals("")) {
|
||||
return ActivityType.INVALID;
|
||||
}
|
||||
if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.WALK)) {
|
||||
return ActivityType.WALKING;
|
||||
} else if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.RUN)) {
|
||||
return ActivityType.RUNNING;
|
||||
} else if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.BIKE)) {
|
||||
return ActivityType.CYCLING;
|
||||
}
|
||||
@@ -96,34 +85,79 @@ public class CalorieUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the track calorie in kcal.
|
||||
* Updates calories for a track and its waypoints.
|
||||
*
|
||||
* @param context the context
|
||||
* @param track the track
|
||||
* @param startTrackPointId the starting track point id. -1L to calculate the
|
||||
* entire track
|
||||
* @return an array of two doubles, first is the track calorie, second is the
|
||||
* last statistics waypoint calorie
|
||||
*/
|
||||
public static double getTrackCalorie(Context context, Track track, long startTrackPointId) {
|
||||
public static double[] updateTrackCalorie(Context context, Track track) {
|
||||
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
ActivityType activityType = getActivityType(context, track.getCategory());
|
||||
|
||||
if (activityType == ActivityType.INVALID) {
|
||||
return 0.0;
|
||||
clearCalorie(myTracksProviderUtils, track);
|
||||
return new double[] { 0.0, 0.0 };
|
||||
}
|
||||
|
||||
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
LocationIterator iterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||
track.getId(), startTrackPointId, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||
TripStatisticsUpdater tripStatisticsUpdater = new TripStatisticsUpdater(
|
||||
TripStatisticsUpdater trackTripStatisticsUpdater = new TripStatisticsUpdater(
|
||||
track.getTripStatistics().getStartTime());
|
||||
TripStatisticsUpdater markerTripStatisticsUpdater = new TripStatisticsUpdater(
|
||||
track.getTripStatistics().getStartTime());
|
||||
int recordingDistanceInterval = PreferencesUtils.getInt(context,
|
||||
R.string.recording_distance_interval_key,
|
||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT);
|
||||
int statsWeight = PreferencesUtils.getInt(
|
||||
context, R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
||||
while (iterator.hasNext()) {
|
||||
tripStatisticsUpdater.addLocation(
|
||||
iterator.next(), recordingDistanceInterval, true, activityType, statsWeight);
|
||||
double weight = PreferencesUtils.getFloat(
|
||||
context, R.string.weight_key, PreferencesUtils.WEIGHT_DEFAULT);
|
||||
LocationIterator locationIterator = null;
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
Waypoint waypoint = null;
|
||||
|
||||
locationIterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||
track.getId(), -1L, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||
cursor = myTracksProviderUtils.getWaypointCursor(track.getId(), -1L, -1);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
/*
|
||||
* Yes, this will skip the first waypoint and that is intentional as the
|
||||
* first waypoint holds the stats for the track.
|
||||
*/
|
||||
waypoint = getNextStatisticsWaypoint(myTracksProviderUtils, cursor);
|
||||
}
|
||||
|
||||
while (locationIterator.hasNext()) {
|
||||
Location location = locationIterator.next();
|
||||
trackTripStatisticsUpdater.addLocation(
|
||||
location, recordingDistanceInterval, true, activityType, weight);
|
||||
markerTripStatisticsUpdater.addLocation(
|
||||
location, recordingDistanceInterval, true, activityType, weight);
|
||||
|
||||
if (waypoint != null && waypoint.getLocation().getTime() == location.getTime()
|
||||
&& waypoint.getLocation().getLatitude() == location.getLatitude()
|
||||
&& waypoint.getLocation().getLongitude() == location.getLongitude()) {
|
||||
waypoint.getTripStatistics()
|
||||
.setCalorie(markerTripStatisticsUpdater.getTripStatistics().getCalorie());
|
||||
myTracksProviderUtils.updateWaypoint(waypoint);
|
||||
markerTripStatisticsUpdater = new TripStatisticsUpdater(location.getTime());
|
||||
waypoint = getNextStatisticsWaypoint(myTracksProviderUtils, cursor);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (locationIterator != null) {
|
||||
locationIterator.close();
|
||||
}
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return tripStatisticsUpdater.getTripStatistics().getCalorie();
|
||||
double trackCalorie = trackTripStatisticsUpdater.getTripStatistics().getCalorie();
|
||||
track.getTripStatistics().setCalorie(trackCalorie);
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
return new double[] {
|
||||
trackCalorie, markerTripStatisticsUpdater.getTripStatistics().getCalorie() };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,141 +171,137 @@ public class CalorieUtils {
|
||||
* @param activityType the activity type
|
||||
*/
|
||||
public static double getCalorie(
|
||||
Location start, Location stop, double grade, int weight, ActivityType activityType) {
|
||||
Location start, Location stop, double grade, double weight, ActivityType activityType) {
|
||||
if (activityType == ActivityType.INVALID) {
|
||||
return 0.0;
|
||||
}
|
||||
return ActivityType.CYCLING == activityType ? getCyclingCalorie(start, stop, grade, weight)
|
||||
: getFootCalorie(start, stop, grade, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cycling calorie in kcal between two locations.
|
||||
*
|
||||
* @param start the start location
|
||||
* @param stop the stop location
|
||||
* @param grade the grade
|
||||
* @param weight the weight in kilogram of the rider plus bike
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static double getCyclingCalorie(Location start, Location stop, double grade, int weight) {
|
||||
// Gets duration in seconds
|
||||
double duration = (double) (stop.getTime() - start.getTime()) * UnitConversions.MS_TO_S;
|
||||
// Get speed in meters per second
|
||||
double speed = (start.getSpeed() + stop.getSpeed()) / 2.0;
|
||||
|
||||
if (grade < 0) {
|
||||
grade = 0.0;
|
||||
}
|
||||
return getCyclingCalorie(speed, grade, weight, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cycling calorie in kcal using the following equation: <br>
|
||||
* P = g * m * Vg * (K1 + s) + K2 * (Va)^2 * Vg
|
||||
* <ul>
|
||||
* <li>P - Power in watt (Joule/second)</li>
|
||||
* <li>g - gravity, using 9.80665 meter/second^2</li>
|
||||
* <li>m - mass of the rider plus bike in kilogram</li>
|
||||
* <li>s - surface grade</li>
|
||||
* <li>Vg - ground relative speed in meter/second</li>
|
||||
* <li>Va - air relative speed. We assume the air speed is zero, so Va is
|
||||
* equal to Vg.</li>
|
||||
* <li>K1 - a constant which represents frictional losses, using 0.0053.</li>
|
||||
* <li>K2 - a constant representing aerodynamic drag, using 0.185.</li>
|
||||
* <li></li>
|
||||
* </ul>
|
||||
*
|
||||
* @param speed the speed in meters per second
|
||||
* @param grade the grade
|
||||
* @param weight weight in kilogram of the rider plus bike
|
||||
* @param duration the duration in seconds
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static double getCyclingCalorie(double speed, double grade, int weight, double duration) {
|
||||
// Get the power in watt (Joule/second)
|
||||
double power = EARTH_GRAVITY * weight * speed * (K1 + grade) + K2 * (speed * speed * speed);
|
||||
|
||||
// Get the calories in kcal
|
||||
return power * duration * UnitConversions.J_TO_KCAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the foot calorie in kcal between two locations.
|
||||
*
|
||||
* @param start the start location
|
||||
* @param stop the stop location
|
||||
* @param grade the grade
|
||||
* @param weight the weight of the user in kilogram
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static double getFootCalorie(Location start, Location stop, double grade, int weight) {
|
||||
// Get speed in meters per second
|
||||
double averageSpeed = (start.getSpeed() + stop.getSpeed()) / 2.0;
|
||||
// Get VO2 in mL/kg/min
|
||||
double vo2 = getFootVo2(averageSpeed, grade);
|
||||
// Duration in minutes
|
||||
// Speed in m/s
|
||||
double speed = (start.getSpeed() + stop.getSpeed()) / 2.0;
|
||||
// Duration in min
|
||||
double duration = (double) (stop.getTime() - start.getTime()) * UnitConversions.MS_TO_S
|
||||
* UnitConversions.S_TO_MIN;
|
||||
/*
|
||||
* Get the calorie. The unit of calorie is kcal which is came from
|
||||
* (mL/kg/min * min * kg * L/mL * kcal/L)
|
||||
*/
|
||||
return vo2 * duration * weight * UnitConversions.ML_TO_L * L_TO_KCAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the foot VO2 value in ml/kg/min.
|
||||
*
|
||||
* @param speed the speed in meters per second
|
||||
* @param grade the grade
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static double getFootVo2(double speed, double grade) {
|
||||
if (grade < 0) {
|
||||
grade = 0.0;
|
||||
if (activityType == ActivityType.CYCLING) {
|
||||
/*
|
||||
* Power in watt (Joule/second). See
|
||||
* http://en.wikipedia.org/wiki/Bicycle_performance.
|
||||
*/
|
||||
double power = EARTH_GRAVITY * weight * speed * (K1 + grade) + K2 * (speed * speed * speed);
|
||||
|
||||
// WorkRate in kgm/min
|
||||
double workRate = power * UnitConversions.W_TO_KGM;
|
||||
|
||||
/*
|
||||
* VO2 in kgm/min/kg 1.8 = oxygen cost of producing 1 kgm/min of power
|
||||
* output. 7 = oxygen cost of unloaded cycling plus resting oxygen
|
||||
* consumption
|
||||
*/
|
||||
double vo2 = (1.8 * workRate / weight) + 7;
|
||||
|
||||
// Calorie in kcal
|
||||
return vo2 * duration * weight * UnitConversions.KGM_TO_KCAL;
|
||||
} else {
|
||||
double vo2 = activityType == ActivityType.RUNNING ? getRunningVo2(speed, grade)
|
||||
: getWalkingVo2(speed, grade);
|
||||
|
||||
/*
|
||||
* Calorie in kcal (mL/kg/min * min * kg * L/mL * kcal/L)
|
||||
*/
|
||||
return vo2 * duration * weight * UnitConversions.ML_TO_L * UnitConversions.L_TO_KCAL;
|
||||
}
|
||||
return speed > CRTICAL_SPEED_RUNNING ? getHighSpeedFootVo2(speed, grade)
|
||||
: getLowSpeedFootVo2(speed, grade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the high speed foot VO2 in ml/kg/min. This equation is appropriate for
|
||||
* speeds greater than 4.5 mph like running.
|
||||
* Clears calorie in the track and its waypoints.
|
||||
*
|
||||
* @param speed the speed in meters per second
|
||||
* @param grade the grade
|
||||
* @param myTracksProviderUtils the my tracks provider utils
|
||||
* @param track the track
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static double getHighSpeedFootVo2(double speed, double grade) {
|
||||
// Change from meters per second to meters per minute
|
||||
speed = speed / UnitConversions.S_TO_MIN;
|
||||
|
||||
/*
|
||||
* 0.2 means oxygen cost per meter of moving each kilogram (kg) of body
|
||||
* weight while running (horizontally). 0.9 means oxygen cost per meter of
|
||||
* moving total body mass against gravity (vertically).
|
||||
*/
|
||||
return 0.2 * speed + 0.9 * speed * Math.abs(grade) + RESTING_VO2;
|
||||
private static void clearCalorie(MyTracksProviderUtils myTracksProviderUtils, Track track) {
|
||||
track.getTripStatistics().setCalorie(0);
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = myTracksProviderUtils.getWaypointCursor(track.getId(), -1L, -1);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
/*
|
||||
* Yes, this will skip the first waypoint and that is intentional as the
|
||||
* first waypoint holds the stats for the track.
|
||||
*/
|
||||
while (cursor.moveToNext()) {
|
||||
Waypoint waypoint = myTracksProviderUtils.createWaypoint(cursor);
|
||||
waypoint.getTripStatistics().setCalorie(0);
|
||||
myTracksProviderUtils.updateWaypoint(waypoint);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the low speed foot VO2 in ml/kg/min. This equation is appropriate for
|
||||
* speed less than 4.5 mph like walking.
|
||||
* Gets the next statistics waypoint from a cursor.
|
||||
*
|
||||
* @param speed the speed in meters per second
|
||||
* @param myTracksProviderUtils the my tracks provider utils
|
||||
* @param cursor the cursor
|
||||
*/
|
||||
private static Waypoint getNextStatisticsWaypoint(
|
||||
MyTracksProviderUtils myTracksProviderUtils, Cursor cursor) {
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
while (cursor.moveToNext()) {
|
||||
Waypoint waypoint = myTracksProviderUtils.createWaypoint(cursor);
|
||||
if (waypoint.getType() == WaypointType.STATISTICS) {
|
||||
return waypoint;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the running VO2 in ml/kg/min. This equation is appropriate for speeds
|
||||
* greater than 5 mi/hr (or 3 mi/hr or greater if the subject is truly
|
||||
* jogging).
|
||||
*
|
||||
* @param speed the speed in m/s
|
||||
* @param grade the grade
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static double getLowSpeedFootVo2(double speed, double grade) {
|
||||
// Change from meters per second to meters per minute
|
||||
private static double getRunningVo2(double speed, double grade) {
|
||||
// Change from m/s to m/min
|
||||
speed = speed / UnitConversions.S_TO_MIN;
|
||||
|
||||
/*
|
||||
* 0.1 means oxygen cost per meter of moving each kilogram (kg) of body
|
||||
* weight while walking (horizontally). 1.8 means oxygen cost per meter of
|
||||
* moving total body mass against gravity (vertically).
|
||||
* 0.2 = oxygen cost per meter of moving each kg of body weight while
|
||||
* running (horizontally). 0.9 = oxygen cost per meter of moving total body
|
||||
* mass against gravity (vertically).
|
||||
*/
|
||||
return 0.1 * speed + 1.8 * speed * Math.abs(grade) + RESTING_VO2;
|
||||
return 0.2 * speed + 0.9 * speed * grade + RESTING_VO2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the walking VO2 in ml/kg/min. This equation is appropriate for speed
|
||||
* from 1.9 to 4 mi/hr.
|
||||
*
|
||||
* @param speed the speed in m/s
|
||||
* @param grade the grade
|
||||
*/
|
||||
private static double getWalkingVo2(double speed, double grade) {
|
||||
// Change from m/s to m/min
|
||||
speed = speed / UnitConversions.S_TO_MIN;
|
||||
|
||||
/*
|
||||
* 0.1 = oxygen cost per meter of moving each kilogram (kg) of body weight
|
||||
* while walking (horizontally). 1.8 = oxygen cost per meter of moving total
|
||||
* body mass against gravity (vertically).
|
||||
*/
|
||||
return 0.1 * speed + 1.8 * speed * grade + RESTING_VO2;
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,9 @@ public class LocationUtils {
|
||||
|
||||
private static final String TAG = LocationUtils.class.getSimpleName();
|
||||
|
||||
private static final long MAX_LOCATION_AGE_MS = 60 * 1000; // 1 minute
|
||||
// 1 minute in milliseconds
|
||||
private static final long MAX_LOCATION_AGE_MS = (long) (UnitConversions.MIN_TO_S
|
||||
* UnitConversions.S_TO_MS);
|
||||
|
||||
private LocationUtils() {}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Utilities to access preferences stored in {@link SharedPreferences}.
|
||||
@@ -106,8 +107,6 @@ public class PreferencesUtils {
|
||||
public static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
|
||||
public static final boolean STATS_SHOW_GRADE_ELEVATION_DEFAULT = false;
|
||||
public static final String STATS_UNITS_DEFAULT = "METRIC";
|
||||
public static final boolean STATS_SHOW_CALORIE_DEFAULT = false;
|
||||
public static final int STATS_WEIGHT_DEFAULT = 65; // in kilogram
|
||||
|
||||
// Track color
|
||||
public static final String TRACK_COLOR_MODE_DEFAULT = "SINGLE";
|
||||
@@ -124,6 +123,10 @@ public class PreferencesUtils {
|
||||
public static final int TRACK_WIDGET_ITEM4_DEFAULT = 2; // average speed
|
||||
public static final int VOICE_FREQUENCY_DEFAULT = 0;
|
||||
|
||||
public static final float WEIGHT_DEFAULT = 65.0f; // in kilogram
|
||||
|
||||
private static final String TAG = PreferencesUtils.class.getSimpleName();
|
||||
|
||||
private PreferencesUtils() {}
|
||||
|
||||
/**
|
||||
@@ -194,6 +197,35 @@ public class PreferencesUtils {
|
||||
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a float preference value.
|
||||
*
|
||||
* @param context the context
|
||||
* @param keyId the key id
|
||||
* @param defaultValue the default value
|
||||
*/
|
||||
public static float getFloat(Context context, int keyId, float defaultValue) {
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||
return sharedPreferences.getFloat(getKey(context, keyId), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a float preference value.
|
||||
*
|
||||
* @param context the context
|
||||
* @param keyId the key id
|
||||
* @param value the value
|
||||
*/
|
||||
@SuppressLint("CommitPrefEdits")
|
||||
public static void setFloat(Context context, int keyId, float value) {
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||
Editor editor = sharedPreferences.edit();
|
||||
editor.putFloat(getKey(context, keyId), value);
|
||||
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a long preference value.
|
||||
*
|
||||
@@ -304,4 +336,37 @@ public class PreferencesUtils {
|
||||
}
|
||||
setString(context, keyId, list + ";" + value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the weight value, always in metric units.
|
||||
*
|
||||
* @param displayValue the display value
|
||||
*/
|
||||
public static void storeWeightValue(Context context, String displayValue) {
|
||||
double value;
|
||||
try {
|
||||
value = Double.parseDouble(displayValue);
|
||||
if (!PreferencesUtils.isMetricUnits(context)) {
|
||||
value = value * UnitConversions.LB_TO_KG;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "invalid value " + displayValue);
|
||||
value = PreferencesUtils.WEIGHT_DEFAULT;
|
||||
}
|
||||
PreferencesUtils.setFloat(context, R.string.weight_key, (float) value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the weight display value.
|
||||
*
|
||||
* @param context the context
|
||||
*/
|
||||
public static double getWeightDisplayValue(Context context) {
|
||||
double value = PreferencesUtils.getFloat(
|
||||
context, R.string.weight_key, PreferencesUtils.WEIGHT_DEFAULT);
|
||||
if (!PreferencesUtils.isMetricUnits(context)) {
|
||||
value = value * UnitConversions.KG_TO_LB;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -26,6 +24,7 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.view.View;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.Locale;
|
||||
@@ -40,9 +39,8 @@ public class StatsUtils {
|
||||
private static final String COORDINATE_DEGREE = "\u00B0";
|
||||
private static final String GRADE_PERCENTAGE = "%";
|
||||
|
||||
private static final String ELEVATION_FORMAT = "%1$.2f";
|
||||
private static final String GRADE_FORMAT = "%1$d";
|
||||
private static final String CALORIES_FORMAT = "%1$.0f";
|
||||
private static final String CALORIES_FORMAT = "%1$,.0f";
|
||||
|
||||
private StatsUtils() {}
|
||||
|
||||
@@ -63,44 +61,48 @@ public class StatsUtils {
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(context);
|
||||
|
||||
// Set speed/pace
|
||||
double speed = isRecording && location != null && location.hasSpeed() ? location.getSpeed()
|
||||
: Double.NaN;
|
||||
setSpeed(context, getView(activity, view, R.id.stats_speed), R.string.stats_speed,
|
||||
R.string.stats_pace, speed, metricUnits, reportSpeed);
|
||||
View speed = getView(activity, view, R.id.stats_speed);
|
||||
speed.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
if (isRecording) {
|
||||
double value = isRecording && location != null && location.hasSpeed() ? location.getSpeed()
|
||||
: Double.NaN;
|
||||
setSpeed(context, speed, R.string.stats_speed, R.string.stats_pace, value, metricUnits,
|
||||
reportSpeed);
|
||||
}
|
||||
|
||||
// Set elevation
|
||||
boolean showGradeElevation = PreferencesUtils.getBoolean(context,
|
||||
R.string.stats_show_grade_elevation_key,
|
||||
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT);
|
||||
boolean showGradeElevation = PreferencesUtils.getBoolean(
|
||||
context, R.string.stats_show_grade_elevation_key,
|
||||
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT) && isRecording;
|
||||
View elevation = getView(activity, view, R.id.stats_elevation);
|
||||
elevation.setVisibility(showGradeElevation ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (showGradeElevation && isRecording) {
|
||||
if (showGradeElevation) {
|
||||
double altitude = location != null && location.hasAltitude() ? location.getAltitude()
|
||||
: Double.NaN;
|
||||
elevation.setVisibility(View.VISIBLE);
|
||||
setElevationValue(context, elevation, -1, altitude, metricUnits);
|
||||
} else {
|
||||
elevation.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// Set coordinate
|
||||
boolean showCoordinate = PreferencesUtils.getBoolean(context,
|
||||
R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT);
|
||||
View coordinateHorizontalLine = getView(activity, view, R.id.stats_coordinate_horizontal_line);
|
||||
boolean showCoordinate = PreferencesUtils.getBoolean(
|
||||
context, R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT)
|
||||
&& isRecording;
|
||||
View coordinateSeparator = getView(activity, view, R.id.stats_coordinate_separator);
|
||||
View coordinateContainer = getView(activity, view, R.id.stats_coordinate_container);
|
||||
|
||||
if (showCoordinate && isRecording) {
|
||||
if (coordinateSeparator != null) {
|
||||
coordinateSeparator.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
coordinateContainer.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (showCoordinate) {
|
||||
double latitude = location != null ? location.getLatitude() : Double.NaN;
|
||||
double longitude = location != null ? location.getLongitude() : Double.NaN;
|
||||
coordinateHorizontalLine.setVisibility(View.VISIBLE);
|
||||
coordinateContainer.setVisibility(View.VISIBLE);
|
||||
setCoordinateValue(
|
||||
context, getView(activity, view, R.id.stats_latitude), R.string.stats_latitude, latitude);
|
||||
setCoordinateValue(context, getView(activity, view, R.id.stats_longitude),
|
||||
R.string.stats_longitude, longitude);
|
||||
} else {
|
||||
coordinateHorizontalLine.setVisibility(View.GONE);
|
||||
coordinateContainer.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,12 +126,12 @@ public class StatsUtils {
|
||||
* @param view the containing view for finding views. If null, the activity
|
||||
* cannot be null
|
||||
* @param tripStatistics the trip statistics
|
||||
* @param trackId the id of track, which is used to set calorie value. Does
|
||||
* not handle the calorie If the value is
|
||||
* {@link PreferencesUtils#RECORDING_TRACK_ID_DEFAULT}
|
||||
* @param activityType the activity type
|
||||
* @param trackIconValue the track icon value or null to hide the track icon
|
||||
* spinner
|
||||
*/
|
||||
public static void setTripStatisticsValues(
|
||||
Context context, Activity activity, View view, TripStatistics tripStatistics, long trackId) {
|
||||
public static void setTripStatisticsValues(Context context, Activity activity, View view,
|
||||
TripStatistics tripStatistics, ActivityType activityType, String trackIconValue) {
|
||||
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(context);
|
||||
|
||||
@@ -138,43 +140,54 @@ public class StatsUtils {
|
||||
setDistanceValue(
|
||||
context, getView(activity, view, R.id.stats_distance), totalDistance, metricUnits);
|
||||
|
||||
// Set calorie
|
||||
double calorie = tripStatistics == null || activityType == ActivityType.INVALID ? Double.NaN
|
||||
: tripStatistics.getCalorie();
|
||||
setCalorie(context, getView(activity, view, R.id.stats_calorie), calorie);
|
||||
|
||||
Spinner spinner = (Spinner) getView(activity, view, R.id.stats_activity_type_icon);
|
||||
spinner.setVisibility(trackIconValue != null ? View.VISIBLE : View.GONE);
|
||||
if (trackIconValue != null) {
|
||||
TrackIconUtils.setIconSpinner(spinner, trackIconValue);
|
||||
}
|
||||
|
||||
// Set total time
|
||||
setTimeValue(context, getView(activity, view, R.id.stats_total_time), R.string.stats_total_time,
|
||||
tripStatistics != null ? tripStatistics.getTotalTime() : -1L);
|
||||
|
||||
// Set moving time
|
||||
setTimeValue(context, getView(activity, view, R.id.stats_moving_time),
|
||||
R.string.stats_moving_time, tripStatistics != null ? tripStatistics.getMovingTime() : -1L);
|
||||
|
||||
// Set average speed/pace
|
||||
double averageSpeed = tripStatistics != null ? tripStatistics.getAverageSpeed() : Double.NaN;
|
||||
setSpeed(context, getView(activity, view, R.id.stats_average_speed),
|
||||
R.string.stats_average_speed, R.string.stats_average_pace, averageSpeed, metricUnits,
|
||||
reportSpeed);
|
||||
|
||||
// Set moving time
|
||||
setTimeValue(context, getView(activity, view, R.id.stats_moving_time),
|
||||
R.string.stats_moving_time, tripStatistics != null ? tripStatistics.getMovingTime() : -1L);
|
||||
|
||||
// Set average moving speed/pace
|
||||
double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed()
|
||||
: Double.NaN;
|
||||
setSpeed(context, getView(activity, view, R.id.stats_average_moving_time),
|
||||
R.string.stats_average_moving_speed, R.string.stats_average_moving_pace, averageMovingSpeed,
|
||||
metricUnits, reportSpeed);
|
||||
|
||||
// Set max speed/pace
|
||||
double maxSpeed = tripStatistics == null ? Double.NaN : tripStatistics.getMaxSpeed();
|
||||
setSpeed(context, getView(activity, view, R.id.stats_max_speed), R.string.stats_max_speed,
|
||||
R.string.stats_fastest_pace, maxSpeed, metricUnits, reportSpeed);
|
||||
|
||||
// Set average moving speed/pace
|
||||
double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed()
|
||||
: Double.NaN;
|
||||
setSpeed(context, getView(activity, view, R.id.stats_average_moving_speed),
|
||||
R.string.stats_average_moving_speed, R.string.stats_average_moving_pace, averageMovingSpeed,
|
||||
metricUnits, reportSpeed);
|
||||
|
||||
// Set grade/elevation
|
||||
boolean showGradeElevation = PreferencesUtils.getBoolean(context,
|
||||
R.string.stats_show_grade_elevation_key,
|
||||
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT);
|
||||
View gradeElevationHorizontalLine = getView(
|
||||
activity, view, R.id.stats_grade_elevation_horizontal_line);
|
||||
View gradeElevationSeparator = getView(activity, view, R.id.stats_grade_elevation_separator);
|
||||
View gradeElevationContainer = getView(activity, view, R.id.stats_grade_elevation_container);
|
||||
|
||||
gradeElevationSeparator.setVisibility(showGradeElevation ? View.VISIBLE : View.GONE);
|
||||
gradeElevationContainer.setVisibility(showGradeElevation ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (showGradeElevation) {
|
||||
gradeElevationHorizontalLine.setVisibility(View.VISIBLE);
|
||||
gradeElevationContainer.setVisibility(View.VISIBLE);
|
||||
// Set grade
|
||||
double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade();
|
||||
double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade();
|
||||
@@ -194,33 +207,6 @@ public class StatsUtils {
|
||||
R.string.stats_min, minElevation, metricUnits);
|
||||
setElevationValue(context, getView(activity, view, R.id.stats_elevation_max),
|
||||
R.string.stats_max, maxElevation, metricUnits);
|
||||
} else {
|
||||
gradeElevationHorizontalLine.setVisibility(View.GONE);
|
||||
gradeElevationContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (trackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
||||
// Set calories
|
||||
boolean showCalorie = PreferencesUtils.getBoolean(
|
||||
context, R.string.stats_show_calorie_key, PreferencesUtils.STATS_SHOW_CALORIE_DEFAULT);
|
||||
View calorieHorizontalLine = getView(activity, view, R.id.stats_calorie_horizontal_line);
|
||||
View calorieContainer = getView(activity, view, R.id.stats_calorie_container);
|
||||
if (showCalorie) {
|
||||
calorieHorizontalLine.setVisibility(View.VISIBLE);
|
||||
calorieContainer.setVisibility(View.VISIBLE);
|
||||
double calories = Double.NaN;
|
||||
if (tripStatistics != null) {
|
||||
calories = tripStatistics.getCalorie();
|
||||
}
|
||||
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
Track track = myTracksProviderUtils.getTrack(trackId);
|
||||
ActivityType activityType = track == null ? ActivityType.INVALID
|
||||
: CalorieUtils.getActivityType(context, track.getCategory());
|
||||
setCalorie(context, getView(activity, view, R.id.stats_calorie), activityType, calories);
|
||||
} else {
|
||||
calorieHorizontalLine.setVisibility(View.GONE);
|
||||
calorieContainer.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,6 +227,19 @@ public class StatsUtils {
|
||||
setItem(context, view, reportSpeed ? speedLabelId : paceLabelId, parts[0], parts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets calorie.
|
||||
*
|
||||
* @param context the context
|
||||
* @param view the containing view
|
||||
* @param calorie the value of calorie
|
||||
*/
|
||||
private static void setCalorie(Context context, View view, double calorie) {
|
||||
String value = Double.isNaN(calorie) ? null
|
||||
: String.format(Locale.getDefault(), CALORIES_FORMAT, calorie);
|
||||
setItem(context, view, R.string.stats_calorie, value, context.getString(R.string.unit_calorie));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets distance value.
|
||||
*
|
||||
@@ -286,11 +285,11 @@ public class StatsUtils {
|
||||
unit = null;
|
||||
} else {
|
||||
if (metricUnits) {
|
||||
value = String.format(Locale.getDefault(), ELEVATION_FORMAT, elevation);
|
||||
value = StringUtils.formatDecimal(elevation);
|
||||
unit = context.getString(R.string.unit_meter);
|
||||
} else {
|
||||
elevation *= UnitConversions.M_TO_FT;
|
||||
value = String.format(Locale.getDefault(), ELEVATION_FORMAT, elevation);
|
||||
value = StringUtils.formatDecimal(elevation);
|
||||
unit = context.getString(R.string.unit_feet);
|
||||
}
|
||||
}
|
||||
@@ -322,28 +321,8 @@ public class StatsUtils {
|
||||
private static void setCoordinateValue(
|
||||
Context context, View view, int labelId, double coordinate) {
|
||||
String value = Double.isNaN(coordinate) || Double.isInfinite(coordinate) ? null
|
||||
: Location.convert(coordinate, Location.FORMAT_DEGREES);
|
||||
setItem(context, view, labelId, value, COORDINATE_DEGREE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets calorie.
|
||||
*
|
||||
* @param context the context
|
||||
* @param view the containing view
|
||||
* @param activityType the activity type
|
||||
* @param calorie the value of calorie
|
||||
*/
|
||||
private static void setCalorie(
|
||||
Context context, View view, ActivityType activityType, double calorie) {
|
||||
if (activityType == ActivityType.INVALID) {
|
||||
view.setVisibility(View.GONE);
|
||||
} else {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
setItem(context, view, R.string.stats_calorie,
|
||||
String.format(Locale.getDefault(), CALORIES_FORMAT, calorie),
|
||||
context.getString(R.string.unit_calorie));
|
||||
}
|
||||
: Location.convert(coordinate, Location.FORMAT_DEGREES) + COORDINATE_DEGREE;
|
||||
setItem(context, view, labelId, value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,7 +334,8 @@ public class StatsUtils {
|
||||
* @param value the value, can be null
|
||||
* @param unit the unit. Null to hide the unit
|
||||
*/
|
||||
private static void setItem(Context context, View view, int labelId, String value, String unit) {
|
||||
private static void setItem(
|
||||
Context context, View view, int labelId, CharSequence value, CharSequence unit) {
|
||||
TextView labelTextView = (TextView) view.findViewById(R.id.stats_label);
|
||||
TextView valueTextView = (TextView) view.findViewById(R.id.stats_value);
|
||||
TextView unitTextView = (TextView) view.findViewById(R.id.stats_unit);
|
||||
|
||||
@@ -81,7 +81,7 @@ public class StringUtils {
|
||||
*/
|
||||
public static String formatElapsedTime(long time) {
|
||||
/*
|
||||
* Temporary workaround for DateUtils.formatElapsedTime(time / 1000). In API
|
||||
* Temporary workaround for DateUtils.formatElapsedTime(time * MS_TO_S). In API
|
||||
* level 17, it returns strings like "1:0:00" instead of "1:00:00", which
|
||||
* breaks several unit tests.
|
||||
*/
|
||||
@@ -91,7 +91,7 @@ public class StringUtils {
|
||||
long hours = 0;
|
||||
long minutes = 0;
|
||||
long seconds = 0;
|
||||
long elapsedSeconds = time / 1000;
|
||||
long elapsedSeconds = (long) (time * UnitConversions.MS_TO_S);
|
||||
|
||||
if (elapsedSeconds >= 3600) {
|
||||
hours = elapsedSeconds / 3600;
|
||||
@@ -149,6 +149,19 @@ public class StringUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatWeight(double value) {
|
||||
return formatDecimal(value, 1);
|
||||
}
|
||||
|
||||
public static String formatDecimal(double value) {
|
||||
return formatDecimal(value, 2);
|
||||
}
|
||||
|
||||
private static String formatDecimal(double value, int precision) {
|
||||
String result = String.format(Locale.getDefault(), "%1$,." + precision + "f", value);
|
||||
return result.replaceAll("[0]*$", "").replaceAll("\\.$", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the distance in an array of two strings. The first string is the
|
||||
* distance. The second string is the unit. The first string is null if the
|
||||
@@ -183,7 +196,7 @@ public class StringUtils {
|
||||
unitId = R.string.unit_feet;
|
||||
}
|
||||
}
|
||||
result[0] = String.format("%.2f", distance);
|
||||
result[0] = formatDecimal(distance);
|
||||
result[1] = context.getString(unitId);
|
||||
return result;
|
||||
}
|
||||
@@ -217,13 +230,13 @@ public class StringUtils {
|
||||
speed *= UnitConversions.KM_TO_MI;
|
||||
}
|
||||
if (reportSpeed) {
|
||||
result[0] = String.format("%.2f", speed);
|
||||
result[0] = StringUtils.formatDecimal(speed);
|
||||
} else {
|
||||
// convert from hours to minutes
|
||||
double pace = speed == 0 ? 0.0 : 60.0 / speed;
|
||||
int minutes = (int) pace;
|
||||
int seconds = (int) Math.round((pace - minutes) * 60.0);
|
||||
result[0] = String.format("%d:%02d", minutes, seconds);
|
||||
result[0] = String.format(Locale.US, "%d:%02d", minutes, seconds);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -301,7 +314,7 @@ public class StringUtils {
|
||||
if (fractional != null) {
|
||||
// Regex ensures fractional part is in (0,1)
|
||||
float fractionalSeconds = Float.parseFloat(fractional);
|
||||
long fractionalMillis = (long) (fractionalSeconds * 1000.0f);
|
||||
long fractionalMillis = (long) (fractionalSeconds * UnitConversions.S_TO_MS);
|
||||
time += fractionalMillis;
|
||||
}
|
||||
|
||||
@@ -350,7 +363,7 @@ public class StringUtils {
|
||||
}
|
||||
int[] parts = new int[3];
|
||||
|
||||
long seconds = time / 1000;
|
||||
long seconds = (long) (time * UnitConversions.MS_TO_S);
|
||||
parts[0] = (int) (seconds % 60);
|
||||
int minutes = (int) (seconds / 60);
|
||||
parts[1] = minutes % 60;
|
||||
|
||||
@@ -21,8 +21,13 @@ import com.google.android.maps.mytracks.R;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -100,10 +105,10 @@ public class TrackIconUtils {
|
||||
*/
|
||||
public static int getIconDrawable(String iconValue) {
|
||||
if (iconValue == null || iconValue.equals("")) {
|
||||
return R.drawable.ic_track_walk;
|
||||
return R.drawable.ic_track_generic;
|
||||
}
|
||||
Pair<Integer, Integer> pair = map.get(iconValue);
|
||||
return pair == null ? R.drawable.ic_track_walk : pair.second;
|
||||
return pair == null ? R.drawable.ic_track_generic : pair.second;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,6 +142,9 @@ public class TrackIconUtils {
|
||||
* @param activityType the activity type
|
||||
*/
|
||||
public static String getIconValue(Context context, String activityType) {
|
||||
if (activityType == null || activityType.equals("")) {
|
||||
return "";
|
||||
}
|
||||
if (inList(context, activityType, airplane)) {
|
||||
return AIRPLANE;
|
||||
}
|
||||
@@ -196,6 +204,35 @@ public class TrackIconUtils {
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void setIconSpinner(Spinner spinner, String iconValue) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayAdapter<StringBuilder> adapter = (ArrayAdapter<StringBuilder>) spinner.getAdapter();
|
||||
StringBuilder stringBuilder = adapter.getItem(0);
|
||||
stringBuilder.delete(0, stringBuilder.length());
|
||||
stringBuilder.append(iconValue);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public static ArrayAdapter<StringBuilder> getIconSpinnerAdapter(
|
||||
final Context context, String iconValue) {
|
||||
return new ArrayAdapter<StringBuilder>(context, android.R.layout.simple_spinner_item,
|
||||
new StringBuilder[] { new StringBuilder(iconValue) }) {
|
||||
@Override
|
||||
public View getView(int position, View convertView, android.view.ViewGroup parent) {
|
||||
ImageView imageView = convertView != null ? (ImageView) convertView
|
||||
: new ImageView(getContext());
|
||||
Bitmap source = BitmapFactory.decodeResource(
|
||||
context.getResources(), TrackIconUtils.getIconDrawable(getItem(position).toString()));
|
||||
if (ApiAdapterFactory.getApiAdapter().isSpinnerBackgroundLight()) {
|
||||
source = TrackIconUtils.invertBitmap(source);
|
||||
}
|
||||
imageView.setImageBitmap(source);
|
||||
imageView.setPadding(4, 4, -4, -4);
|
||||
return imageView;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the activity type is in the list.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2013 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.util;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Utilities for updating track.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class TrackUtils {
|
||||
|
||||
private TrackUtils() {}
|
||||
|
||||
public static void updateTrack(Context context, Track track, String name, String category,
|
||||
String description, MyTracksProviderUtils myTracksProviderUtils,
|
||||
TrackRecordingServiceConnection trackRecordingServiceConnection, boolean newWeight) {
|
||||
if (name != null) {
|
||||
track.setName(name);
|
||||
}
|
||||
boolean updateCalorie = false;
|
||||
if (category != null) {
|
||||
updateCalorie = !category.equals(track.getCategory()) || newWeight;
|
||||
track.setCategory(category);
|
||||
track.setIcon(TrackIconUtils.getIconValue(context, category));
|
||||
}
|
||||
|
||||
if (description != null) {
|
||||
track.setDescription(description);
|
||||
}
|
||||
track.setModifiedTime(System.currentTimeMillis());
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
|
||||
if (updateCalorie) {
|
||||
if (track.getId() == PreferencesUtils.getLong(context, R.string.recording_track_id_key)) {
|
||||
// Update calorie through track recording service
|
||||
TrackRecordingServiceConnectionUtils.updateCalorie(trackRecordingServiceConnection);
|
||||
} else {
|
||||
CalorieUtils.updateTrackCalorie(context, track);
|
||||
}
|
||||
}
|
||||
|
||||
boolean driveSync = PreferencesUtils.getBoolean(
|
||||
context, R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT);
|
||||
if (driveSync) {
|
||||
PreferencesUtils.addToList(context, R.string.drive_edited_list_key,
|
||||
PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT, String.valueOf(track.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,13 @@ public class UnitConversions {
|
||||
|
||||
private UnitConversions() {}
|
||||
|
||||
// multiplication factor to convert milliliters to liters
|
||||
public static final double ML_TO_L = 1 / 1000.0;
|
||||
// Time
|
||||
|
||||
// multiplication factor to convert seconds to milliseconds
|
||||
public static final double S_TO_MS = 1000.0;
|
||||
|
||||
// multiplication factor to convert milliseconds to seconds
|
||||
public static final double MS_TO_S = 1 / 1000.0;
|
||||
public static final double MS_TO_S = 1 / S_TO_MS;
|
||||
|
||||
// multiplication factor to convert minutes to seconds
|
||||
public static final double MIN_TO_S = 60.0;
|
||||
@@ -42,15 +44,11 @@ public class UnitConversions {
|
||||
// multiplication factor to convert minutes to hours
|
||||
public static final double MIN_TO_HR = 1 / HR_TO_MIN;
|
||||
|
||||
// Distance
|
||||
|
||||
// multiplication factor to convert kilometers to miles
|
||||
public static final double KM_TO_MI = 0.621371192;
|
||||
|
||||
// multiplication factor to convert kilograms to pounds
|
||||
public static final double KG_TO_LB = 2.2046;
|
||||
|
||||
// multiplication factor to convert pounds to kilograms
|
||||
public static final double LB_TO_KG = 1 / KG_TO_LB;
|
||||
|
||||
// multiplication factor to convert miles to kilometers
|
||||
public static final double MI_TO_KM = 1 / KM_TO_MI;
|
||||
|
||||
@@ -60,13 +58,11 @@ public class UnitConversions {
|
||||
// multiplication factor to convert feet to miles
|
||||
public static final double FT_TO_MI = 1 / MI_TO_FT;
|
||||
|
||||
// multiplication factor to covert kilometers to meters
|
||||
public static final double KM_TO_M = 1000.0;
|
||||
|
||||
// multiplication factor to convert meters to kilometers
|
||||
public static final double M_TO_KM = 1 / 1000.0;
|
||||
|
||||
public static final double KM_TO_M = 1 / M_TO_KM;
|
||||
|
||||
// multiplication factor to convert meters per second to kilometers per hour
|
||||
public static final double MS_TO_KMH = 3.6;
|
||||
public static final double M_TO_KM = 1 / KM_TO_M;
|
||||
|
||||
// multiplication factor to convert meters to miles
|
||||
public static final double M_TO_MI = M_TO_KM * KM_TO_MI;
|
||||
@@ -74,12 +70,33 @@ public class UnitConversions {
|
||||
// multiplication factor to convert meters to feet
|
||||
public static final double M_TO_FT = M_TO_MI * MI_TO_FT;
|
||||
|
||||
// Weight
|
||||
|
||||
// multiplication factor to convert kilograms to pounds
|
||||
public static final double KG_TO_LB = 2.2046;
|
||||
|
||||
// multiplication factor to convert pounds to kilograms
|
||||
public static final double LB_TO_KG = 1 / KG_TO_LB;
|
||||
|
||||
// Calories
|
||||
|
||||
// multiplication factor to convert milliliters to liters
|
||||
public static final double ML_TO_L = 1 / 1000.0;
|
||||
|
||||
// multiplication factor to convert liter to kcal
|
||||
public static final double L_TO_KCAL = 5.0;
|
||||
|
||||
// multiplication factor to convert watt to kgm/min
|
||||
public static final double W_TO_KGM = 6.12;
|
||||
|
||||
// multiplication factor to convert kgm to kcal
|
||||
public static final double KGM_TO_KCAL = 1 / 427.0;
|
||||
|
||||
// Others
|
||||
|
||||
// multiplication factor to convert meters per second to kilometers per hour
|
||||
public static final double MS_TO_KMH = M_TO_KM / (S_TO_MIN * MIN_TO_HR);
|
||||
|
||||
// multiplication factor to convert degrees to radians
|
||||
public static final double DEG_TO_RAD = Math.PI / 180.0;
|
||||
|
||||
// multiplication factor to convert Kcal to joules.
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user