diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/content/sensor/SensorDataSet.java b/myTracks/src/main/java/com/google/android/apps/mytracks/content/sensor/SensorDataSet.java
index 497232387..61a994aab 100644
--- a/myTracks/src/main/java/com/google/android/apps/mytracks/content/sensor/SensorDataSet.java
+++ b/myTracks/src/main/java/com/google/android/apps/mytracks/content/sensor/SensorDataSet.java
@@ -64,6 +64,14 @@ public final class SensorDataSet {
return creationTimestamp;
}
+ /**
+ * Is the data recent considering the current time.
+ * @param maxAge the maximal age in milliseconds.
+ */
+ public boolean isRecent(long maxAge) {
+ return creationTimestamp + maxAge > System.currentTimeMillis();
+ }
+
public boolean hasBatteryLevel() {
return batteryLevel != DATA_UNAVAILABLE;
}
diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/MarkerDetailFragment.java b/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/MarkerDetailFragment.java
index e48363551..bb6002cf7 100644
--- a/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/MarkerDetailFragment.java
+++ b/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/MarkerDetailFragment.java
@@ -248,11 +248,9 @@ public class MarkerDetailFragment extends Fragment {
setName(R.id.marker_detail_waypoint_name, hasPhoto);
TextView category = getView().findViewById(R.id.marker_detail_waypoint_category);
- ListItemUtils.setTextView(
- getActivity(), category, StringUtils.getCategory(waypoint.getCategory()), hasPhoto);
+ ListItemUtils.setTextView(getActivity(), category, StringUtils.getCategory(waypoint.getCategory()), hasPhoto);
- TextView description = getView()
- .findViewById(R.id.marker_detail_waypoint_description);
+ TextView description = getView().findViewById(R.id.marker_detail_waypoint_description);
ListItemUtils.setTextView(getActivity(), description, waypoint.getDescription(), hasPhoto);
setLocation(R.id.marker_detail_waypoint_location, hasPhoto);
diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/StatsFragment.java b/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/StatsFragment.java
index 6a5f42db6..aab3b19c8 100644
--- a/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/StatsFragment.java
+++ b/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/StatsFragment.java
@@ -19,6 +19,7 @@ package com.google.android.apps.mytracks.fragments;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -36,11 +37,15 @@ import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.TrackDataListener;
import com.google.android.apps.mytracks.content.TrackDataType;
import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
+import com.google.android.apps.mytracks.services.ITrackRecordingService;
+import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.apps.mytracks.util.TrackIconUtils;
+import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
@@ -59,8 +64,11 @@ public class StatsFragment extends Fragment implements TrackDataListener {
private TrackDataHub trackDataHub;
private Handler handlerUpdateUI;
+ private TrackRecordingServiceConnection trackRecordingServiceConnection;
+
private Location lastLocation = null;
private TripStatistics lastTripStatistics = null;
+ private SensorDataSet sensorDataSet = null;
private String category = "";
private int recordingGpsAccuracy = PreferencesUtils.RECORDING_GPS_ACCURACY_DEFAULT;
@@ -70,12 +78,15 @@ public class StatsFragment extends Fragment implements TrackDataListener {
if (isResumed() && isSelectedTrackRecording()) {
if (!isSelectedTrackPaused() && lastTripStatistics != null) {
StatsUtils.setTotalTimeValue(getActivity(), System.currentTimeMillis() - lastTripStatistics.getStopTime() + lastTripStatistics.getTotalTime());
+ updateSensorDataUI();
}
+
handlerUpdateUI.postDelayed(this, UnitConversions.ONE_SECOND);
}
}
};
+
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.stats, container, false);
@@ -85,7 +96,9 @@ public class StatsFragment extends Fragment implements TrackDataListener {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
handlerUpdateUI = new Handler();
-
+ trackRecordingServiceConnection = new TrackRecordingServiceConnection(getContext(), null);
+ TrackRecordingServiceConnectionUtils.startConnection(getContext(), trackRecordingServiceConnection);
+
Spinner activityTypeIcon = getView().findViewById(R.id.stats_activity_type_icon);
activityTypeIcon.setAdapter(TrackIconUtils.getIconSpinnerAdapter(getActivity(), ""));
activityTypeIcon.setOnTouchListener(new View.OnTouchListener() {
@@ -125,6 +138,12 @@ public class StatsFragment extends Fragment implements TrackDataListener {
handlerUpdateUI.removeCallbacks(updateTotalTime);
}
+ @Override
+ public void onStop() {
+ super.onStop();
+ trackRecordingServiceConnection.unbind();
+ }
+
@Override
public void onTrackUpdated(final Track track) {
if (isResumed()) {
@@ -286,6 +305,22 @@ public class StatsFragment extends Fragment implements TrackDataListener {
return trackDataHub != null && trackDataHub.isSelectedTrackPaused();
}
+ /**
+ * Tries to fetch most recent {@link SensorDataSet} {@link com.google.android.apps.mytracks.services.sensors.SensorManager}.
+ */
+ private void updateSensorDataUI() {
+ ITrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
+ if (trackRecordingService == null) {
+ Log.d(STATS_FRAGMENT_TAG, "Cannot get the track recording service.");
+ sensorDataSet = null;
+ } else {
+ //TODO sensorState = trackRecordingService.getSensorState();
+ sensorDataSet = trackRecordingService.getSensorData();
+ }
+
+ StatsUtils.setSensorData(getActivity(), getActivity(), sensorDataSet, isSelectedTrackRecording());
+ }
+
/**
* Updates the UI.
*/
@@ -293,5 +328,6 @@ public class StatsFragment extends Fragment implements TrackDataListener {
String trackIconValue = TrackIconUtils.getIconValue(activity, category);
StatsUtils.setTripStatisticsValues(activity, activity, null, lastTripStatistics, trackIconValue);
StatsUtils.setLocationValues(activity, activity, null, lastLocation, isSelectedTrackRecording());
+ updateSensorDataUI();
}
}
diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/services/sensors/SensorManager.java b/myTracks/src/main/java/com/google/android/apps/mytracks/services/sensors/SensorManager.java
index 4c6cdbeab..9ab6a415c 100644
--- a/myTracks/src/main/java/com/google/android/apps/mytracks/services/sensors/SensorManager.java
+++ b/myTracks/src/main/java/com/google/android/apps/mytracks/services/sensors/SensorManager.java
@@ -31,9 +31,10 @@ import java.util.TimerTask;
*/
public abstract class SensorManager {
+ public static final long MAX_SENSOR_DATE_SET_AGE = 5000;
+ public static final long MAX_SENSOR_STATE_AGE = 20000;
+
private static final String TAG = SensorManager.class.getSimpleName();
- private static final long MAX_SENSOR_DATE_SET_AGE = 5000;
- private static final long MAX_SENSOR_STATE_AGE = 20000;
private static final int RETRY_PERIOD = 20000;
private SensorState sensorState = SensorState.NONE;
@@ -132,6 +133,6 @@ public abstract class SensorManager {
if (sensorDataSet == null) {
return false;
}
- return (System.currentTimeMillis() - sensorDataSet.getCreationTime()) < MAX_SENSOR_DATE_SET_AGE;
+ return sensorDataSet.isRecent(MAX_SENSOR_DATE_SET_AGE);
}
}
diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/util/StatsUtils.java b/myTracks/src/main/java/com/google/android/apps/mytracks/util/StatsUtils.java
index 7faca3f58..e2faf54fa 100644
--- a/myTracks/src/main/java/com/google/android/apps/mytracks/util/StatsUtils.java
+++ b/myTracks/src/main/java/com/google/android/apps/mytracks/util/StatsUtils.java
@@ -23,6 +23,8 @@ import android.view.View;
import android.widget.Spinner;
import android.widget.TextView;
+import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
+import com.google.android.apps.mytracks.services.sensors.SensorManager;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.maps.mytracks.R;
@@ -51,8 +53,7 @@ public class StatsUtils {
* @param location the location
* @param isRecording true if recording
*/
- public static void setLocationValues(
- Context context, Activity activity, View view, Location location, boolean isRecording) {
+ public static void setLocationValues(Context context, Activity activity, View view, Location location, boolean isRecording) {
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
boolean reportSpeed = PreferencesUtils.isReportSpeed(context);
@@ -61,29 +62,22 @@ public class StatsUtils {
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);
+ 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) && isRecording;
+ 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) {
- double altitude = location != null && location.hasAltitude() ? location.getAltitude()
- : Double.NaN;
+ double altitude = location != null && location.hasAltitude() ? location.getAltitude() : Double.NaN;
setElevationValue(context, elevation, -1, altitude, metricUnits);
}
// Set coordinate
- boolean showCoordinate = PreferencesUtils.getBoolean(
- context, R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT)
- && isRecording;
+ boolean showCoordinate = isRecording && PreferencesUtils.getBoolean(context, R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT);
View coordinateSeparator = getView(activity, view, R.id.stats_coordinate_separator);
View coordinateContainer = getView(activity, view, R.id.stats_coordinate_container);
@@ -95,10 +89,19 @@ public class StatsUtils {
if (showCoordinate) {
double latitude = location != null ? location.getLatitude() : Double.NaN;
double longitude = location != null ? location.getLongitude() : Double.NaN;
- 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);
+ 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);
+ }
+ }
+
+ public static void setSensorData(Context context, Activity activity, SensorDataSet sensorDataSet, boolean isRecording) {
+ {
+ // SensorDataSet: heart rate
+ View view = getView(activity, null, R.id.stats_sensor_heart_rate_value);
+ view.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE);
+ if (isRecording) {
+ setHeartRateValue(context, view, sensorDataSet);
+ }
}
}
@@ -109,8 +112,7 @@ public class StatsUtils {
* @param totalTime the total time
*/
public static void setTotalTimeValue(Activity activity, long totalTime) {
- setTimeValue(activity, activity.findViewById(R.id.stats_total_time), R.string.stats_total_time,
- totalTime);
+ setTimeValue(activity, activity.findViewById(R.id.stats_total_time), R.string.stats_total_time, totalTime);
}
/**
@@ -281,6 +283,21 @@ public class StatsUtils {
setItem(context, view, labelId, value, null);
}
+ /**
+ * Sets a heart rate value (sensor)
+ *
+ * @param context the context
+ * @param view the containing view
+ * @param sensorDataSet the sensorDataSet
+ */
+ private static void setHeartRateValue(Context context, View view, SensorDataSet sensorDataSet) {
+ String heartRate = context.getString(R.string.value_unknown);
+ if (sensorDataSet != null && sensorDataSet.hasHeartRate() && sensorDataSet.isRecent(SensorManager.MAX_SENSOR_DATE_SET_AGE)) {
+ heartRate = StringUtils.formatDecimal(sensorDataSet.getHeartRate(), 0);
+ }
+ setItem(context, view, R.string.sensor_state_heart_rate, heartRate, context.getString(R.string.sensor_unit_beats_per_minute));
+ }
+
/**
* Sets an item.
*
@@ -328,6 +345,7 @@ public class StatsUtils {
* @param view the containing view
* @param id the id
*/
+ //TODO What is the difference between the two cases? Is it (still) necessary?
private static View getView(Activity activity, View view, int id) {
if (activity != null) {
return activity.findViewById(id);
diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/util/StringUtils.java b/myTracks/src/main/java/com/google/android/apps/mytracks/util/StringUtils.java
index 1a50cfff3..95c8244ea 100644
--- a/myTracks/src/main/java/com/google/android/apps/mytracks/util/StringUtils.java
+++ b/myTracks/src/main/java/com/google/android/apps/mytracks/util/StringUtils.java
@@ -152,7 +152,11 @@ public class StringUtils {
}
public static String formatDecimal(double value) {
- String result = String.format(Locale.getDefault(), "%1$,.2f", value);
+ return StringUtils.formatDecimal(value, 2);
+ }
+
+ public static String formatDecimal(double value, int decimalPlaces) {
+ String result = String.format(Locale.getDefault(), "%1$,." + decimalPlaces +"f", value);
return result.replaceAll("[0]*$", "").replaceAll("\\.$", "");
}
diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/util/TrackRecordingServiceConnectionUtils.java b/myTracks/src/main/java/com/google/android/apps/mytracks/util/TrackRecordingServiceConnectionUtils.java
index c8ccba66d..11785313f 100644
--- a/myTracks/src/main/java/com/google/android/apps/mytracks/util/TrackRecordingServiceConnectionUtils.java
+++ b/myTracks/src/main/java/com/google/android/apps/mytracks/util/TrackRecordingServiceConnectionUtils.java
@@ -133,8 +133,7 @@ public class TrackRecordingServiceConnectionUtils {
* @param trackRecordingServiceConnection the track recording service
* connection
*/
- public static void startConnection(
- Context context, TrackRecordingServiceConnection trackRecordingServiceConnection) {
+ public static void startConnection(Context context, TrackRecordingServiceConnection trackRecordingServiceConnection) {
trackRecordingServiceConnection.bindIfStarted();
if (!isRecordingServiceRunning(context)) {
resetRecordingState(context);
diff --git a/myTracks/src/main/res/layout/stats_content.xml b/myTracks/src/main/res/layout/stats_content.xml
index 29b7d484d..4fc3b6550 100644
--- a/myTracks/src/main/res/layout/stats_content.xml
+++ b/myTracks/src/main/res/layout/stats_content.xml
@@ -134,4 +134,19 @@ limitations under the License.
android:id="@+id/stats_longitude"
layout="@layout/stats_small_item" />
+
+
+
+
+
+
\ No newline at end of file
diff --git a/myTracks/src/main/res/values/do_not_translate.xml b/myTracks/src/main/res/values/do_not_translate.xml
index f0811b8ab..209a6cfec 100644
--- a/myTracks/src/main/res/values/do_not_translate.xml
+++ b/myTracks/src/main/res/values/do_not_translate.xml
@@ -81,6 +81,8 @@ Google은 이용자에 대한 위치정보의 이용∙제공사실을 위치정
NONE
POLAR
ZEPHYR
+ RPM
+ BPM
DYNAMIC
FIXED
SINGLE
diff --git a/myTracks/src/main/res/values/strings.xml b/myTracks/src/main/res/values/strings.xml
index 1d7f57865..99a92312d 100644
--- a/myTracks/src/main/res/values/strings.xml
+++ b/myTracks/src/main/res/values/strings.xml
@@ -1392,7 +1392,7 @@ limitations under the License.
%1$d bpm