diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackEditActivity.java b/MyTracks/src/com/google/android/apps/mytracks/TrackEditActivity.java index 89d82dbee..a04688b0d 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/TrackEditActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/TrackEditActivity.java @@ -184,24 +184,25 @@ public class TrackEditActivity extends AbstractMyTracksActivity save.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - track.setName(name.getText().toString()); String category = activityType.getText().toString(); - if (!category.equals(track.getCategory())) { - // TODO Is there no race condition when setCalorie is called. - double[] calories = CalorieUtils.calculateTrackCalorie(getApplicationContext(), track, - category); - - track.getTripStatistics().setCalorie(calories[0]); - TrackRecordingServiceConnectionUtils.updateCalorie(trackRecordingServiceConnection, - calories); - } - track.setCategory(category); + track.setName(name.getText().toString()); track.setIcon(TrackIconUtils.getIconValue(TrackEditActivity.this, category)); track.setDescription(description.getText().toString()); track.setModifiedTime(System.currentTimeMillis()); - myTracksProviderUtils.updateTrack(track); - boolean driveSync = PreferencesUtils.getBoolean( - TrackEditActivity.this, R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT); + if (!category.equals(track.getCategory())) { + track.setCategory(category); + // If edit recording track. + if (track.getId() == PreferencesUtils.getLong(getApplicationContext(), + R.string.recording_track_id_key)) { + TrackRecordingServiceConnectionUtils.updateCalorie(trackRecordingServiceConnection, + track); + } else { + CalorieUtils.updateTrackStatistics(getApplicationContext(), track); + myTracksProviderUtils.updateTrack(track); + } + } + boolean driveSync = PreferencesUtils.getBoolean(TrackEditActivity.this, + R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT); if (driveSync) { PreferencesUtils.addToList(TrackEditActivity.this, R.string.drive_edited_list_key, PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT, String.valueOf(track.getId())); diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java index 72e5c5542..0b2ee435b 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java @@ -36,6 +36,7 @@ import com.google.android.apps.mytracks.services.tasks.PeriodicTaskExecutor; import com.google.android.apps.mytracks.services.tasks.SplitPeriodicTaskFactory; import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatisticsUpdater; +import com.google.android.apps.mytracks.util.CalorieUtils; import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.apps.mytracks.util.LocationUtils; import com.google.android.apps.mytracks.util.PreferencesUtils; @@ -1001,7 +1002,8 @@ public class TrackRecordingService extends Service { try { Uri uri = myTracksProviderUtils.insertTrackPoint(location, track.getId()); long trackPointId = Long.parseLong(uri.getLastPathSegment()); - trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context); + trackTripStatisticsUpdater.addLocationCalorie(location, recordingDistanceInterval, + CalorieUtils.getActivityType(context, track.getId()), context); markerTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context); updateRecordingTrack(track, trackPointId, LocationUtils.isValidLocation(location)); } catch (SQLiteException e) { @@ -1335,21 +1337,21 @@ public class TrackRecordingService extends Service { } @Override - public void updateCalorie(double calorieTotal, double calorieCurrentSegment) { + public void updateTripStatistics(Track track) { if (!canAccess()) { return; } - trackRecordingService.updateCalorie(calorieTotal, calorieCurrentSegment); + trackRecordingService.updateTripStatistics(track); } } - + /** - * Updates the calorie value. + * Updates the TripStatistics of current recording track after the current + * track is edited by user. * - * @param calorieTotal the calorie value of entire track - * @param calorieCurrentSegment the calorie value of current segment + * @param track the current recording track */ - public void updateCalorie(final double calorieTotal, final double calorieCurrentSegment) { + public void updateTripStatistics(final Track track) { if (myTracksLocationManager == null || executorService == null || !myTracksLocationManager.isAllowed() || executorService.isShutdown() || executorService.isTerminated()) { @@ -1358,7 +1360,9 @@ public class TrackRecordingService extends Service { executorService.submit(new Runnable() { @Override public void run() { - trackTripStatisticsUpdater.updateCalorie(calorieTotal, calorieCurrentSegment); + trackTripStatisticsUpdater = CalorieUtils.updateTrackStatistics(getApplicationContext(), + track); + MyTracksProviderUtils.Factory.get(context).updateTrack(track); } }); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdater.java b/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdater.java index 98683dab8..5510f0a01 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdater.java +++ b/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdater.java @@ -130,13 +130,27 @@ public class TripStatisticsUpdater { * @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); + PreferencesUtils.getLong(context, R.string.recording_track_id_key)), 0, false); + } + + /** + * Adds a location and calculate calorie. Only calculate calorie when add + * location to a recording track. + * + * @param location the location + * @param minRecordingDistance the min recording distance + * @param activityType the activity type + * @param context the context to get the weight and track category + */ + public void addLocationCalorie(Location location, int minRecordingDistance, + ActivityType activityType, Context context) { + int weight = PreferencesUtils.getInt(context, R.string.stats_weight_key, + PreferencesUtils.STATS_WEIGHT_DEFAULT); + addLocation(location, minRecordingDistance, activityType, weight, true); } /** @@ -146,13 +160,13 @@ public class TripStatisticsUpdater { * @param minRecordingDistance the min recording distance * @param activityType the activity type of current track * @param weight the weight to calculate calorie + * @param isCalculateCalorie true means calculate calorie */ @VisibleForTesting void addLocation(Location location, int minRecordingDistance, ActivityType activityType, - int weight) { + int weight, boolean isCalculateCalorie) { // Always update time updateTime(location.getTime()); - if (!LocationUtils.isValidLocation(location)) { // Either pause or resume marker if (location.getLatitude() == PAUSE_LATITUDE) { @@ -214,26 +228,16 @@ public class TripStatisticsUpdater { location.getTime(), location.getSpeed(), lastLocation.getTime(), lastLocation.getSpeed()); } - // Update calorie - double calorie = CalorieUtils.getCalorie(lastMovingLocation, location, - gradeBuffer.getAverage(), weight, activityType); - currentSegment.addCalorie(calorie); - + if (isCalculateCalorie) { + // Update calorie + double calorie = CalorieUtils.getCalorie(lastMovingLocation, location, + gradeBuffer.getAverage(), weight, activityType); + currentSegment.addCalorie(calorie); + } lastLocation = location; lastMovingLocation = location; } - /** - * Updates the calorie value. - * - * @param calorieTotal the calorie value of entire track - * @param calorieCurrentSegment the calorie value of current segment - */ - public void updateCalorie(double calorieTotal, double calorieCurrentSegment) { - tripStatistics.setCalorie(calorieTotal); - currentSegment.setCalorie(calorieCurrentSegment); - } - /** * Gets the smoothed elevation over several readings. The elevation readings * is noisy so the smoothed elevation is better than the raw elevation for diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/CalorieUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/CalorieUtils.java index e89d4ed2f..0adea8b89 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/CalorieUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/CalorieUtils.java @@ -18,8 +18,6 @@ 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.services.TrackRecordingService; -import com.google.android.apps.mytracks.stats.DoubleBuffer; import com.google.android.apps.mytracks.stats.TripStatisticsUpdater; import com.google.android.maps.mytracks.R; import com.google.common.annotations.VisibleForTesting; @@ -280,69 +278,30 @@ public class CalorieUtils { * @param context the context * @param track the track to calculate * @param category the category of track - * @return a double array of calorie value and the size of this array is 2. - * The first value is the calorie of entire track and the second value - * is the calorie of current segment + * @return the TripStatisticsUpdater of track */ - public static double[] calculateTrackCalorie(Context context, Track track, String category) { - double[] calories = {0.0, 0.0}; - ActivityType activityType = getActivityType(context, category); - if (activityType == ActivityType.INVALID) { - return calories; - } + public static TripStatisticsUpdater updateTrackStatistics(Context context, Track track) { + ActivityType activityType = getActivityType(context, track.getCategory()); - double calorieTotal = 0.0; - double calorieCurrentSegment = 0.0; MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context); long trackId = track.getId(); LocationIterator points = providerUtils.getTrackPointLocationIterator(trackId, -1, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY); - DoubleBuffer gradeBuffer = new DoubleBuffer(TripStatisticsUpdater.GRADE_SMOOTHING_FACTOR); - - if (points.hasNext()) { - Location start = points.next(); - - while (points.hasNext()) { - Location stop = points.next(); - - if (stop.getLatitude() == TrackRecordingService.PAUSE_LATITUDE - || stop.getLatitude() == TrackRecordingService.RESUME_LATITUDE) { - calorieCurrentSegment = 0.0; - continue; - } - - double grade = updateGrade(gradeBuffer, stop.distanceTo(start), - stop.getAltitude() - start.getAltitude()); - double calorieAdded = getCalorie(start, stop, grade, PreferencesUtils.getInt(context, - R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT), activityType); - calorieTotal += calorieAdded; - calorieCurrentSegment += calorieAdded; - start = stop; + TripStatisticsUpdater tripStatisticsUpdater = new TripStatisticsUpdater(track + .getTripStatistics().getStartTime()); + while (points.hasNext()) { + if (activityType == ActivityType.INVALID) { + tripStatisticsUpdater.addLocation(points.next(), PreferencesUtils.getInt(context, + R.string.recording_distance_interval_key, + PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT), context); + } else { + tripStatisticsUpdater.addLocationCalorie(points.next(), PreferencesUtils.getInt(context, + R.string.recording_distance_interval_key, + PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT), activityType, context); } } - calories[0] = calorieTotal; - calories[1] = calorieCurrentSegment; - return calories; + track.setTripStatistics(tripStatisticsUpdater.getTripStatistics()); + return tripStatisticsUpdater; } - - /** - * Updates a grade reading. - * - * @param gradeBuffer - * @param distance - * @param rise - * @return - */ - private static double updateGrade(DoubleBuffer gradeBuffer, float distance, Double rise) { - double grade = 0; - if (rise > 0 && distance > 0) { - gradeBuffer.setNext(rise / distance); - grade = gradeBuffer.getAverage(); - } else { - gradeBuffer.setNext(0); - } - return grade; - } - } \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/TrackRecordingServiceConnectionUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/TrackRecordingServiceConnectionUtils.java index 754c0ef8f..165ce6b84 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/TrackRecordingServiceConnectionUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/TrackRecordingServiceConnectionUtils.java @@ -17,6 +17,7 @@ package com.google.android.apps.mytracks.util; import com.google.android.apps.mytracks.TrackEditActivity; +import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.WaypointCreationRequest; import com.google.android.apps.mytracks.services.ITrackRecordingService; import com.google.android.apps.mytracks.services.TrackRecordingService; @@ -197,21 +198,17 @@ public class TrackRecordingServiceConnectionUtils { /** * Updates the calorie of current recording track. * - * @param trackRecordingServiceConnection the TrackRecordingServiceConnection - * instance - * @param calories a double array of calorie value and the size of this array - * is 2. The first value is the calorie of entire track and the - * second value is the calorie of current segment + * @param trackRecordingServiceConnection + * @param track the current recording track */ - public static void updateCalorie(TrackRecordingServiceConnection trackRecordingServiceConnection, - double[] calories) { + public static void updateCalorie(TrackRecordingServiceConnection trackRecordingServiceConnection, Track track) { ITrackRecordingService trackRecordingService = trackRecordingServiceConnection .getServiceIfBound(); if (trackRecordingService == null) { Log.d(TAG, "Unable to update calorie, no track recording service"); } else { try { - trackRecordingService.updateCalorie(calories[0], calories[1]); + trackRecordingService.updateTripStatistics(track); } catch (RemoteException e) { Log.e(TAG, "Unable to update calorie", e); } catch (IllegalStateException e) { diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/Track.aidl b/MyTracksLib/src/com/google/android/apps/mytracks/content/Track.aidl new file mode 100644 index 000000000..67d3d1de5 --- /dev/null +++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/Track.aidl @@ -0,0 +1,2 @@ +package com.google.android.apps.mytracks.content; +parcelable Track; \ No newline at end of file diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/services/ITrackRecordingService.aidl b/MyTracksLib/src/com/google/android/apps/mytracks/services/ITrackRecordingService.aidl index 9fb0c9bb4..3a369af0e 100644 --- a/MyTracksLib/src/com/google/android/apps/mytracks/services/ITrackRecordingService.aidl +++ b/MyTracksLib/src/com/google/android/apps/mytracks/services/ITrackRecordingService.aidl @@ -16,6 +16,7 @@ package com.google.android.apps.mytracks.services; import com.google.android.apps.mytracks.content.WaypointCreationRequest; +import com.google.android.apps.mytracks.content.Track; /** * MyTracks service. @@ -108,10 +109,9 @@ interface ITrackRecordingService { int getSensorState(); /** - * Updates the calorie value. + * Updates the TripStatistics of current recording track. * - * @param calorieTotal the calorie value of entire track - * @param calorieCurrentSegment the calorie value of current segment + * @param track the current recording track */ - void updateCalorie(double calorieTotal, double calorieCurrentSegment); + void updateTripStatistics(in Track track); } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdaterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdaterTest.java index 0aef3dc5b..c457f4758 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdaterTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdaterTest.java @@ -226,7 +226,7 @@ public class TripStatisticsUpdaterTest extends TestCase { startTime + (timeOffset + i) * TEN_SECONDS); tripStatisticsUpdater.addLocation(location, PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, ActivityType.FOOT, - PreferencesUtils.STATS_WEIGHT_DEFAULT); + PreferencesUtils.STATS_WEIGHT_DEFAULT, true); tripStatistics = tripStatisticsUpdater.getTripStatistics(); assertEquals((timeOffset + i) * TEN_SECONDS, tripStatistics.getTotalTime()); @@ -273,7 +273,7 @@ public class TripStatisticsUpdaterTest extends TestCase { locationOffset, locationOffset * .001, 0, startTime + (i + timeOffset) * TEN_SECONDS); tripStatisticsUpdater.addLocation(location, PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, ActivityType.FOOT, - PreferencesUtils.STATS_WEIGHT_DEFAULT); + PreferencesUtils.STATS_WEIGHT_DEFAULT, false); tripStatistics = tripStatisticsUpdater.getTripStatistics(); assertEquals((i + timeOffset) * TEN_SECONDS, tripStatistics.getTotalTime()); @@ -311,7 +311,7 @@ public class TripStatisticsUpdaterTest extends TestCase { startTime + (timeOffset + i) * TEN_SECONDS); tripStatisticsUpdater.addLocation(location, PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, ActivityType.FOOT, - PreferencesUtils.STATS_WEIGHT_DEFAULT); + PreferencesUtils.STATS_WEIGHT_DEFAULT, true); tripStatistics = tripStatisticsUpdater.getTripStatistics(); assertTrue(tripStatistics.getMovingTime() <= tripStatistics.getTotalTime());