Heart Rate Tracking with the Off-body Sensor

Battery consumption is a critical factor when developing applications that use device sensors. To prolong battery life, the Samsung Health Sensor SDK allows you to implement batching trackers, which send multiple data points in a single callback event. Another way you can extend battery life is by stopping sensor tracking when it is not needed, such as when the watch is not being worn.

This blog describes the “HR Tracker” sample application, which implements the batching heart rate tracker in combination with the off-body sensor. The application enables heart rate tracking only when the watch is worn. If the user tries to start tracking without wearing the watch, they are informed to put it on. If the watch is removed during tracking, the tracking is stopped. If you have a Galaxy Watch4 or higher device running Wear OS powered by Samsung, you can download the sample application and test it on your device.

HR Tracker v1.2.0
(139.3 KB) Sep 14 , 2024

Prerequisites

To implement off-body sensor and heart rate tracking in the application:

  • In the AndroidManifest.xml file for the application, declare the body sensors permission:
<uses-permission android:name="android.permission.BODY_SENSORS" />
  • In the HeartRateActivity.java application code file, check whether the user has granted permission to use the body sensors on their Galaxy Watch. If they have not, request it.
if (checkSelfPermission(Manifest.permission.BODY_SENSORS) 
		== PackageManager.PERMISSION_DENIED) {
  requestPermissions(new String[]{Manifest.permission.BODY_SENSORS}, OFFBODY_REQUEST);
}

Implementing on and off-body detection

To detect when the Galaxy Watch is being worn on the wrist:

  • Create an instance of the SensorManager class:
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  • From the SensorManager class, create an instance of the Sensor class that contains the low-latency off-body sensor:
offBodySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT);
  • In the onResume() method, register an event listener for changes to the offBodySensor value when the application is in the foreground:
mSensorManager.registerListener(SkinTemperatureActivity.this,
offBodySensor, SensorManager.SENSOR_DELAY_NORMAL);
  • In the onPause() method, unregister the event listener when the application is in the background:
mSensorManager.unregisterListener(this);
  • Override the onSensorChanged() method to react to the offBodyData sensor value change when the watch is worn or removed from the wrist:
    Because the sensor value is a float, you must convert the value to an integer:
final float offBodyDataFloat = sensorEvent.values[0];
final int offBodyData = Math.round(offBodyDataFloat);

If the value of offBodyData is 1, the watch is being worn. We set the variable, which describes worn status, to true:

deviceWorn.set(true);

If the value of offBodyData is 0, the watch is not being worn. Set the status variable to false and if measurement was being done at that time - end it and notify the user:

deviceWorn.set(false);
if(isMeasurementRunning.get()) {
	endMeasurement();
    Toast.makeText(
    	this,
    	R.string.device_removed_during_measurement,
    	Toast.LENGTH_LONG).show();
}

In the sample application - a toast message is shown, if the watch is removed while tracker is working:


Watch removed during measurement

Measuring the heart rate

To measure the user’s heart rate:

  • Check which trackers are supported on the watch using the checkCapabilities() method:
final List<HealthTrackerType> availableTrackers = healthTrackingService
  .getTrackingCapability()
  .getSupportHealthTrackerTypes();
  • And return if the heart rate tracker is supported:
return availableTrackers.contains(HealthTrackerType.HEART_RATE_CONTINUOUS);
  • Initialize the heart rate tracker:
heartRateTracker = healthTrackingService.getHealthTracker(HealthTrackerType.HEART_RATE_CONTINUOUS);
  • When "Measure" button is pressed - check if watch is being worn before starting tracker and cancel execution if its not:
if(!deviceWorn.get()) {
	Toast.makeText(this, R.string.device_not_worn, Toast.LENGTH_SHORT).show();
    return;
}
  • Set an event listener to receive and handle the tracked heart rate data:
if (!isHandlerRunning) {
  heartRateHandler.post(() -> heartRateTracker.setEventListener(heartRateListener));
  isHandlerRunning = true;
}
  • A listener is an object, which will process incoming data. In this blog we will focus on one of the functions included in it - onDataReceived(). It contains data gathered by the Samsung Health Sensor SDK as list of DataPoint type:
public void onDataReceived(@NonNull List<DataPoint> list) {
  for (DataPoint data : list) {
    updateHeartRate(data);
  }
}
  • For the heart rate sensor, each tracking result consists of a heart rate reading in beats per minute and its status parameter, and a list of inter-beat intervals and the corresponding status for each value. Because we are interested in the heart rate, extract the beats per minute reading and status:
final int status = data.getValue(ValueKey.HeartRateSet.HEART_RATE_STATUS);
int heartRateValue = data.getValue(ValueKey.HeartRateSet.HEART_RATE);
trackerDataSubject.notifyHeartRateTrackerObservers(status, heartRateValue);

If the heart rate reading was successful, the status value is “1”. To interpret other status values, see the API documentation.

  • Display the heart rate and status value on the application screen:
activityHeartRateBinding.txtHeartRateBPMValue.setText(
  String.format(Locale.getDefault(), "%d", heartRateValue));
activityHeartRateBinding.txtHeartRateStatusValue.setText(
  String.format(Locale.getDefault(), "%d", status));


"HR Tracker" sample application UI

  • If the measurement is stopped by either user input, or watch being removed - stop the heart rate tracker:
if (heartRateListener != null) {
  heartRateListener.stopTracker();
}

This demonstration has shown how you can combine multiple strategies to enhance battery life when implementing sensor tracking in your watch applications, such as using batching tracker, and to disable tracking when the user is not wearing the device. We encourage you to try doing it by yourself and explore other available features provided by Samsung Health Sensor SDK.