Exercise statistics monitoring

Samsung Developer

Tracking exercise progress throughout its duration can be a problematic task requiring a lot of work from the developer. Health Services available on a Samsung Galaxy Watch provide a precise and convenient way to gather statistics.

In this blog post we cover different ways to gather exercise data. We created an example application called Exercise Monitor which gathers statistics about your heart rate and speed while running on a treadmill. In the application we use two ways to gather statistics: StatisticalDataPoint for speed and manual heart rate tracking for comparison. You can download it here.

We also include an example in this blog using CumulativeDataPoint to gather statistics.

The basics of connecting to Health Services are covered in the blog Using Health Services on Galaxy Watch.

Let's start by setting up your exercise then continue by working with the exercise data.

Tracking data with StatisticalDataPoint

To obtain a StatisticalDataPoint object, we need to read aggregated metrics in the exercise configuration builder:

exerciseCapabilitiesSet = result.getExerciseTypeCapabilities(exerciseType).getSupportedDataTypes();
exerciseConfigBuilder = ExerciseConfig.builder()
	.setExerciseType(exerciseType)
	.setDataTypes(exerciseCapabilitiesSet)
	.setAggregateDataTypes(exerciseCapabilitiesSet);

After that we can read these metrics from ExerciseUpdate:

Map<DataType, AggregateDataPoint> aggregateMap = update.getLatestAggregateMetrics();

Then we have to read the appropriate DataType from the map. In this case—speed:

AggregateDataPoint aggregateSpeed = aggregateMap.get(DataType.SPEED);

The AggregateDataPoint object that is obtained can be an instance of two classes—either StatisticalDataPoint or CumulativeDataPoint (which we cover later):

StatisticalDataPoint sdpSpeed = (StatisticalDataPoint) aggregateSpeed;

From there we can easily read all important statistical data:

Double minSpeed = sdpSpeed.getMin().asDouble();
Double maxSpeed = sdpSpeed.getMax().asDouble();
Double avgSpeed = sdpSpeed.getAverage().asDouble();

And use them however we like in the application, for example updating text on labels:

txtMinSpeed.setText(String.format("Min speed: %.1f km/h", minSpeed));
txtMaxSpeed.setText(String.format("Max speed: %.1f km/h", maxSpeed));
txtAvgSpeed.setText(String.format("Average speed: %.1f km/h", avgSpeed));

That’s all we need to do—easy to read and fast to implement.

In this case we have only read exercise data, but statistics can be obtained from other Health Services areas as well.

Tracking data manually

Now let's compare tracking data with StatisticalDataPoint to tracking heart rate manually.

First we need to create appropriate global variables required to track data—especially for the average heart rate that requires information about count samples we gather throughout exercising:

double hrMin = 1000, hrMax = 0, hrSum = 0;
int hrCount = 0;

Since our application assumes that we can exercise multiple times, we need to reset these global variables each time we stop and start an exercise. Therefore, we need a separate function that resets the variables each time we start an exercise:

void init() {
    hrCount = 0;
    hrMin = 1000;
    hrMax = 0;
    hrSum = 0;
    txtMinHR = binding.txtMinHR;
    txtMinSpeed = binding.txtMinSpeed;
    txtMaxHR = binding.txtMaxHR;
    txtMaxSpeed = binding.txtMaxSpeed;
    txtAvgHR = binding.txtAvgHR;
    txtAvgSpeed = binding.txtAvgSpeed;
}

We are ready to work on reading data from ExerciseUpdate. First we get the latest readings:

Map<DataType, List<DataPoint>> dataMap = update.getLatestMetrics();

Then we read HeartRate DataType from the map:

List<DataPoint> hrPoints = dataMap.get(DataType.HEART_RATE_BPM);

This returns a list of Heart Rates registered since the previous ExerciseUpdate callback. We have to iterate through every element and compare its values to our statistical points:

for (int i = 0; i < hrPoints.size(); i++) {
    double curVal = hrPoints.get(i).getValue().asDouble();
    if (curVal == 0)
        continue;
    hrCount++;
    hrSum += curVal;
    if (curVal < hrMin)
        hrMin = curVal;
    if (curVal > hrMax)
        hrMax = curVal;
}

This covers min and max values. As for the average, we have to remember that not every ExerciseUpdate may contain heart rate readings. If it doesn’t, we need to prevent division by 0:

if (hrCount == 0)
    return;
double avgHr = hrSum / hrCount;

Now we are ready to update our text labels—with the exception of the minimum heart rate. If there were no readings, we leave it at 0 instead of updating it to the initialized value:

txtAvgHR.setText(String.format("Average HR: %.0f BPM", avgHr));
if (hrMin < 1000)
    txtMinHR.setText(String.format("Min HR: %.0f BPM", hrMin));
txtMaxHR.setText(String.format("Max HR: %.0f BPM", hrMax));

Tracking data with CumulativeDataPoint

The third option to gather data statistics is using CumulativeDataPoint. It is not used in the Exercise Monitor sample application, but we present an example application in this post. One example CumulativeDataPoint can be used for is repetition statistics, like counting deadlift or dumbbell curl repetitions throughout sets. We start similarly to StatisticalDataPoint by gathering the latest aggregate metrics. But, this time we read the repetition count and cast it to CumulativeDataPoint:

Map<DataType, AggregateDataPoint> aggregateMap = update.getLatestAggregateMetrics();
CumulativeDataPoint cdpRepetitions = (CumulativeDataPoint) aggregateReps;

Now we can measure total repetitions done throughout sets, as well as the workout start and end time:

Long totalReps = cdpRepetitions.getTotal().asLong();
Instant startTime = cdpRepetitions.getStartTime();
Instant endTime = cdpRepetitions.getEndTime();

Enjoy your adventure creating an application that will track anything you want!

We have shown you three ways of gathering exercise statistics. We encourage you to use StatisticalDataPoint or CumulativeDataPoint whenever possible, as they are well-designed to track exercise progress and might significantly simplify development of your fitness app.

Now you are ready to start gathering aggregated exercise statistics using Health Services data in the background in your application on Galaxy Watch with Wear OS Powered by Samsung. We encourage you to experiment on your own with data you wish to track and exercises you want to perform and see how easy and convenient it is!