Migration Guide from Samsung Health SDK for Android to Samsung Health Data SDK

Following the release of Samsung Health Data SDK, Samsung Health SDK for Android will be deprecated in few months. After this transition, partner apps that currently use Samsung Health SDK for Android need to transition to Samsung Health Data SDK.

Benefits of Migrating to Samsung Health Data SDK

Samsung Health Data SDK enables apps to access health data in the Samsung Health app on Android smartphones. Not only does it offer the functionality as Samsung Health SDK for Android, but it also provides various additional advantages. Compared to Samsung Health SDK for Android, Samsung Health Data SDK applies the service logic displayed in the Samsung Health app's trackers and provides more specialized data from the app. This allows health service providers to gain a better understanding of users' health indicators.

For example, to retrieve the same step count data displayed in the Samsung Health app when using Samsung Health SDK for Android, you need to:

  • Set the data type as StepDailyTrend.
  • Set filters for both:
    • The time period
    • SOURCE_TYPE_ALL

This ensures that you receive the same step count data that`s displayed in the Samsung Health app.

Samsung Health SDK for Android code


val healthDataResolver = HealthDataResolver(healthDataStore, null)

val date = LocalDate
    .now()
    .atStartOfDay()
    .toInstant(ZoneOffset.UTC)
    .toEpochMilli()

val filter = Filter.and(
    Filter.eq(StepDailyTrend.DAY_TIME, date),
    Filter.eq(StepDailyTrend.SOURCE_TYPE, StepDailyTrend.SOURCE_TYPE_ALL)
)

val stepsRequest = HealthDataResolver.ReadRequest.Builder()
    .setDataType(StepDailyTrend.HEALTH_DATA_TYPE)
    .setFilter(filter)
    .build()

With Samsung Health Data SDK, you can simplify a data request by utilizing the total aggregator and only applying a time filter. This data request allows you to retrieve the daily total step count displayed in the Samsung Health app without considering the potential oversight of setting the source type to `all'.

Samsung Health Data SDK code


val startTime = LocalDate.now().atStartOfDay()
val endTime = LocalDateTime.now()
val localTimeFilter = LocalTimeFilter.of(startTime, endTime)
val stepsRequest = DataType.StepsType.TOTAL.requestBuilder
    .setLocalTimeFilter(localTimeFilter)
    .build()

Samsung Health Data SDK provides various goal data types, such as step goal, sleep goals, and active calories burned goal. Goal data types help to provide appropriate guidance to users.

Samsung Health Data SDK can read, write, update, and delete health data in the Samsung Health app. It can also retrieve associated data related to specific data. For example, the Samsung Health app continuously measures blood oxygen and skin temperature during sleep. Samsung Health Data SDK allows you to easily retrieve blood oxygen and skin temperature data related to this specific sleep data.

Samsung Health SDK for Android will remain operational for at least 2 years after its deprecation. After a certain period, this SDK will be removed, so we recommend updating your app to use Samsung Health Data SDK instead.

Development process

Previously Samsung Health SDK for Android required developers to submit requires a partner request to get access to be applied for and approved before use. Now with Samsung Health Data SDK you can download and use the SDK in developer mode without submitting a partner request. To enhance the convenience of more developers, the Samsung Health Data SDK has improved its developer mode functionality. If you only need to read the Samsung Health app's data, you can activate the developer mode and proceed with development and testing without requiring the partner request. If you want to test writing data to the Samsung Health app using the Samsung Health Data SDK or to distribute your app, you need to submit a partner request registration is necessary.

If you want to see the detailed process for developing an app with the Samsung Health Data SDK can be found on, please refer to the process page.

Checking supported data types of Samsung Health Data SDK

Before you start using Samsung Health Data SDK, please, compare it with Samsung Health SDK for Android and its existing data types to determine whether the data types you want to use in your app are supported and what additional data can be utilized.

Category

Data type of the Samsung Health SDK for Android SDK

Corresponding data type in the Samsung Health Data SDK

Activity

HealthConstants.Exercise

ExerciseType

HealthConstants.FloorsClimbed

FloorsClimbedType

HealthConstants.StepDailyTrend (read-only)

StepsType (read-only)

HealthConstants.StepCount (read-only)

Not provided

Not provided

StepGoalType (read-only)

Not provided

ActivitySummaryType (read-only)

Not provided

ActiveCaloriesBurnedGoalType (read-only)

Not provided

ActiveTimeGoalType (read-only)

Food intake

HealthConstants.Nutrition

NutritionType

Not provided

NutritionGoalType (read-only)

HealthConstants.WaterIntake

WaterIntakeType

Not provided

WaterIntakeGoalType (read-only)

Rest

HealthConstants.Sleep

SleepType

HealthConstants.SleepStage

Not provided

Not provided

SleepGoalType (read-only)

Healthcare

HealthConstants.BloodGlucose

BloodGlucoseType

HealthConstants.BloodPressure

BloodPressureType

HealthConstants.BodyTemperature

BodyTemperature

HealthConstants.HeartRate

HeartRateType

HealthConstants.OxygenSaturationType

BloodOxygenType

HealthConstants.Weight

BodyCompositionType

Not provided

SkinTemperature

Score

Not provided

EnergyScoreType (read-only)

User profile

HealthUserProfile (read-only)

UserProfileDataType (read-only)

Checking the user experience

To access health data from Samsung Health Data SDK, you need to receive data permissions and obtain user consent. In order to do that, please, follow the same process as Samsung Health SDK for Android. You can request data permissions at requesting data permissions.

Note
When using both SDKs together, the data permissions of each SDK are displayed to the user, which can result in an inconvenient UI for the user. Hence, we recommend to use Samsung Health Data SDK.

Data Permission of Samsung Health SDK for Android

Data Permission of Samsung Health Data SDK

Getting Started

1) Download Samsung Health Data SDK

Visit Samsung Health Data SDK page to download Samsung Health Data SDK.

2) Enabling Samsung Health Data SDK’s developer mode

If you only need to read data from Samsung Health app, you can enable the developer mode feature without submitting an additional partner request. Refer to the developer mode for instructions on how to enable it.

If you want to write data to Samsung Health app, you need to submit a partner request.

3) Importing Samsung Health Data SDK's library

Remove the library of Samsung Health SDK for Android from your app project.

  • samsung-health-data-a.b.c.aar

And add Samsung Health Data SDK's library to the app/libs folder.

  • samsung-health-data-api-a.b.c.aar (Note that 'a.b.c' is the SDK's version.)

4) Update app manifest

If your app's manifest has the element for the Samsung Health app, please remove it.

App manifest - Remove the element for Samsung Health SDK for Android

    <manifest ... >
    <queries>
        <package android:name="com.sec.android.app.shealth" />
    </queries>

</manifest>

If the app manifest has the element lines related to health data permissions of Samsung Health SDK for Android, please remove it.

App manifest - Remove the data permission declarations for Samsung Health SDK for Android

<manifest ... >

    <application ... >
        <meta-data android:name="com.samsung.android.health.permission.read"
            android:value="com.samsung.health.exercise;com.samsung.shealth.step_daily_trend"/>
        <meta-data android:name="com.samsung.android.health.permission.write"
    </application>

</manifest>

5) Gradle settings

In the app/builde.gradle, remove the dependency for Samsung Health SDK for Android.

app/build.gradle - Remove the dependency for Samsung Health SDK for Android

dependencies {
    implementation files('src/main/libs/samsung-health-data-1.5.1.aar')
}

Add the dependency for Samsung Health Data SDK instead.

app/build.gradle - Add the dependency for Samsung Health Data SDK

dependencies {
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"))))
}

Add the gson library in the dependency.

app/build.gradle - Add the dependency for Samsung Health Data SDK

dependencies {
    implementation "com.google.code.gson:gson:2.9.0"
}

And apply the kotlin-parcelize plugin to the app/build.gradle.

app/build.gradle - Add the plugin for Samsung Health Data SDK

plugins {
    id("kotlin-parcelize")
}

6) Connecting with Samsung Health

To access health data in the Samsung Health app, you need to connect the SDK with the Samsung Health app. If the Samsung Health app is not installed or you have an earlier version of the Samsung Health app than the supported version, an exception occurs after the connection request. If it is a resolvable exception, call the resolve() API is to resolve the exception.

Below is an example code snippet when using Samsung Health SDK for Android.

Connecting with Samsung Health with Samsung Health SDK for Android

lateinit var healthDataStore: HealthDataStore

fun connect(activity: Activity) {
    healthDataStore = HealthDataStore(context, object : HealthDataStore.ConnectionListener {
        override fun onConnected() {
            Log.i(APP_TAG, "Health data service is connected")
        }

        override fun onConnectionFailed(error: HealthConnectionErrorResult) {
            if (error.hasResolution()) {
                error.resolve(activity)
            } else {
                Log.i(APP_TAG, "Health data service is not available")
            }
        }

        override fun onDisconnected() {
            Log.i(APP_TAG, "Health data service is disconnected")
        }
    })

    runCatching {
        healthDataStore.connectService()
    }.onFailure { error ->
        error.message?.let { Log.i(APP_TAG, it) }
    }
}

To connect to the Samsung Health app using Samsung Health Data SDK, you can do so as shown in the code below.

Connecting with Samsung Health with Samsung Health Data SDK

lateinit var healthDataStore: HealthDataStore

fun connect(activity: Activity) {
    runCatching {
        healthDataStore = HealthDataService.getStore(context)
    }.onSuccess {
        Log.i(APP_TAG, "Health data service is connected")
    }.onFailure { error ->
        if (error is ResolvablePlatformException && error.hasResolution) {
            error.resolve(activity)
        }
        // handle other types of HealthDataException
        error.message?.let { Log.i(APP_TAG, it) }
    }
}

7) Requesting data permissions

After you have successfully connected to the Samsung Health app, you need to request data permissions for the health data you want to access from the user. Upon obtaining an explicit consent from the user, you will be able to access the health data.

Before requesting data permission, check if the user has already granted the data permission. If the required data permission has not been obtained, proceed to request the necessary data permission.

The following code is an example of requesting data permissions to read daily step count, nutrition, and user profile data when using Samsung Health SDK for Android.

Requesting data permission with Samsung Health SDK for Android

private val permissionListener: HealthResultHolder.ResultListener<PermissionResult> =
    HealthResultHolder.ResultListener<PermissionResult> { result ->
        if (result.resultMap.values.contains(FALSE)) {
            Log.i(APP_TAG, "Not all required permissions granted")
        } else {
            Log.i(APP_TAG, "All required permissions granted")
        }
    }

fun requestPermissions(activity: Activity, healthDataStore: HealthDataStore) {
    val permissionSet = setOf(
        PermissionKey(
            StepDailyTrend.HEALTH_DATA_TYPE,
            HealthPermissionManager.PermissionType.READ
        ),
        PermissionKey(
            Nutrition.HEALTH_DATA_TYPE,
            HealthPermissionManager.PermissionType.READ
        ),
        PermissionKey(
            HealthConstants.USER_PROFILE_DATA_TYPE,
            HealthPermissionManager.PermissionType.READ
        )
    )
    val permissionManager = HealthPermissionManager(healthDataStore)

    runCatching {
        val grantedPermissions = permissionManager.isPermissionAcquired(permissionSet)

        if (grantedPermissions.values.all { it }) {
            Log.i(APP_TAG, "All required permissions granted")
        } else {
            Log.i(APP_TAG, "Not all required permissions granted")
            permissionManager.requestPermissions(permissionSet, activity)
                .setResultListener(permissionListener)
        }
    }.onFailure { error ->
        error.message?.let { Log.i(APP_TAG, it) }
    }
}

When the above code is executed, the following screenshot shows the data permission popup displayed to the user.

When using the Samsung Health Data SDK, you can do the following:

Requesting data permission with Samsung Health Data SDK

suspend fun requestPermissions(healthDataStore: HealthDataStore, activity: Activity) {
    val permissionSet = setOf(
        Permission.of(DataTypes.STEPS, AccessType.READ),
        Permission.of(DataTypes.NUTRITION, AccessType.READ),
        Permission.of(DataTypes.USER_PROFILE, AccessType.READ)
    )
    val grantedPermissions = healthDataStore.getGrantedPermissions(permissionSet)

    if (grantedPermissions.containsAll(permissionSet)) {
        Log.i(APP_TAG, "All required permissions granted")
    } else {
        healthDataStore.requestPermissions(permissionSet, activity)
    }
}

When requesting data permissions with Samsung Health Data SDK, the following screenshot will be displayed to the user.

8) Data Request

Asynchronous request

Asynchronous operations allow the application to continue processing other tasks without waiting for the current task to complete. It prevents the main thread from being blocked. It enhances user experience by keeping the application interactive during long-running tasks and supports efficient handling of concurrent operations.

Below you can see a code example of when using Samsung Health SDK for Android to make an asynchronous request.

Asynchronous request when with Samsung Health SDK for Android

fun readStepsAsync(healthDataStore: HealthDataStore) {
    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val date = LocalDate
        .now()
        .atStartOfDay()
        .toInstant(ZoneOffset.UTC)
        .toEpochMilli()

    val filter = Filter.and(
        Filter.eq(StepDailyTrend.DAY_TIME, date),
        Filter.eq(StepDailyTrend.SOURCE_TYPE, StepDailyTrend.SOURCE_TYPE_ALL)
    )

    val stepsRequest = HealthDataResolver.ReadRequest.Builder()
        .setDataType(StepDailyTrend.HEALTH_DATA_TYPE)
        .setFilter(filter)
        .build()

    try {
        healthDataResolver.read(stepsRequest).setResultListener { result ->
            try {
                val iterator = result.iterator()

                if (iterator.hasNext()) {
                    val healthData = iterator.next()
                    val stepCount = healthData.getInt(StepDailyTrend.COUNT)
                    Log.i(MainActivity.APP_TAG, "Step count: $stepCount")
                }
            } finally {
                result.close()
            }
        }
    } catch (exception: Exception) {
        exception.message?.let { Log.i(MainActivity.APP_TAG, it) }
    }
}

When using Samsung Health Data SDK, you can perform the same operation as follows. Use an API that includes Async.

Asynchronous request with Samsung Health Data SDK

fun readStepsAsync(healthDataStore: HealthDataStore, activity: Activity) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val localTimeFilter = LocalTimeFilter.of(startTime, endTime)
    val stepsRequest = DataType.StepsType.TOTAL.requestBuilder
        .setLocalTimeFilter(localTimeFilter)
        .build()

    healthDataStore.aggregateDataAsync(stepsRequest).setCallback(
        Looper.getMainLooper(),
        { result ->
            val stepCount = result.dataList.first().value
            Log.i(MainActivity.APP_TAG, "Step count: $stepCount")
        }) { error ->
        if (error is ResolvablePlatformException && error.hasResolution) {
            error.resolve(activity)
        }
    }
}

Synchronous request

Synchronous operations execute tasks sequentially, requiring the application to wait for the current task to complete before proceeding to the next. While this approach is simple to implement and ensures a predictable execution flow, it can block the main thread. This makes synchronous operations more suitable for straightforward, short tasks rather than complex or concurrent processes.

To perform synchronous operations when using Samsung Health SDK for Android, you can use the await() API.

Synchronous request with Samsung Health SDK for Android

fun readStepsSync(healthDataStore: HealthDataStore) {
    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val date = LocalDate
        .now()
        .atStartOfDay()
        .toInstant(ZoneOffset.UTC)
        .toEpochMilli()

    val filter = Filter.and(
        Filter.eq(StepDailyTrend.DAY_TIME, date),
        Filter.eq(StepDailyTrend.SOURCE_TYPE, StepDailyTrend.SOURCE_TYPE_ALL)
    )

    val stepsRequest = HealthDataResolver.ReadRequest.Builder()
        .setDataType(StepDailyTrend.HEALTH_DATA_TYPE)
        .setFilter(filter)
        .build()

    try {
        healthDataResolver.read(stepsRequest).await().run {
            try {
                val iterator = iterator()

                if (iterator.hasNext()) {
                    val healthData = iterator.next()
                    val stepCount = healthData.getInt(StepDailyTrend.COUNT)
                    Log.i(MainActivity.APP_TAG, "Step count: $stepCount")
                }
            } finally {
                close()
            }
        }
    } catch (exception: Exception) {
        exception.message?.let { Log.i(MainActivity.APP_TAG, it) }
    }
}

For synchronous operations involving Samsung Health Data SDK, please, use the following approach.

Synchronous request with Samsung Health Data SDK

suspend fun readStepsSync(healthDataStore: HealthDataStore) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val stepsRequest = DataType.StepsType.TOTAL.requestBuilder
        .setLocalTimeFilterWithGroup(
            LocalTimeFilter.Companion.of(startTime, endTime),
            LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1)
        )
        .build()

    try {
        val readResult = healthDataStore.aggregateData(stepsRequest)
        val stepCount = readResult.dataList.first().value
        Log.i(MainActivity.APP_TAG, "Step count: $stepCount")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

9) Implementing and testing app

Accessing the health data is required by the app to test to ensure the functionality works properly. For detailed information on accessing health data, refer to accessing health data.

10) Partner request before distributing your app

The developer mode of Samsung Health Data SDK is a feature provided only for development purposes. To ensure that an app that`s using Samsung Health Data SDK functions properly without enabling developer mode, you need to submit a partner request through the developer site before distributing your app on app market places. After partner app approval, the app's detailed information will be registered in Samsung's system.

Accessing Health data

Steps

Samsung Health measures step data from smartphones with Samsung Health installed and from connected Galaxy wearable devices, such as the Galaxy Watch, Galaxy Fit, or Galaxy Ring. It aggregates and eliminates duplicate data to provide daily step counts. Step count data is read-only.

The corresponding steps data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.StepDailyTrend (read-only)
HealthConstants.StepCount (read-only)

StepsType (read-only)

Here is an example of code that reads today's total step count when using Samsung Health SDK for Android.

Reading today's total steps with Samsung Health SDK for Android

fun readTodayStepCountData(healthDataStore: HealthDataStore) {
    val startTime = LocalDate
        .now()
        .atStartOfDay()
        .toInstant(ZoneOffset.UTC)
        .toEpochMilli()

    val filter = Filter.and(
        Filter.eq(StepDailyTrend.DAY_TIME, startTime),
        Filter.eq(StepDailyTrend.SOURCE_TYPE, StepDailyTrend.SOURCE_TYPE_ALL)
    )

    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val request = HealthDataResolver.ReadRequest.Builder()
        .setDataType(StepDailyTrend.HEALTH_DATA_TYPE)
        .setFilter(filter)
        .build()

    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                val iterator = result.iterator()

                if (iterator.hasNext()) {
                    val healthData = iterator.next()
                    val totalCount = healthData.getInt(StepDailyTrend.COUNT)
                    Log.i(MainActivity.APP_TAG, "Today steps count: $totalCount")
                } else {
                    Log.i(MainActivity.APP_TAG, "No step data available")

The code to retrieve today's total step count when using Samsung Health Data SDK is as follows.

Reading today's total steps with Samsung Health Data SDK

suspend fun readTodayStepCountData(healthDataStore: HealthDataStore) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val readRequest = DataType.StepsType.TOTAL.requestBuilder
        .setLocalTimeFilter(LocalTimeFilter.of(startTime, endTime))
        .build()

    try {
        val readResult = healthDataStore.aggregateData(readRequest)
        val data = readResult.dataList.first()
        val totalCount = data.value
        Log.i(MainActivity.APP_TAG, "Today steps count: $totalCount")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Exercise

The Samsung Health app records the user's exercise data. When the user wears a Galaxy Watch, Galaxy Fit, or Galaxy Ring and records exercise data, the app records their heart rate, exercise speed, and distance.

The corresponding exercise data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.Exercise

ExerciseType

Example code for reading today's exercise data when using Samsung Health SDK for Android is as follows.

Reading exercise data with Samsung Health SDK for Android

fun readTodayExercise(healthDataStore: HealthDataStore) {
    val startTime = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()
    val endTime =
        LocalDate.now().plusDays(1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()

    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val readRequest = HealthDataResolver.ReadRequest.Builder()
        .setDataType(Exercise.HEALTH_DATA_TYPE)
        .setLocalTimeRange(
            FloorsClimbed.START_TIME,
            FloorsClimbed.TIME_OFFSET,
            startTime,
            endTime
        )
        .build()

    try {
        healthDataResolver.read(readRequest).setResultListener { result ->
            try {
                val iterator = result.iterator()

                iterator.forEach { healthData ->
                    val exerciseType = healthData.getInt(Exercise.EXERCISE_TYPE)
                    val duration = healthData.getLong(Exercise.DURATION)
                    val calories = healthData.getFloat(Exercise.CALORIE)
                    Log.i(
                        MainActivity.APP_TAG,
                        "Exercise type: $exerciseType, duration: $duration, calories: $calories"
                    )
                }
            } finally {
                result.close()
            }
        }
    } catch (exception: Exception) {
        exception.message?.let { Log.i(MainActivity.APP_TAG, it) }
    }
}

Example code for reading today's exercise data when using Samsung Health Data SDK is as follows.

Reading exercise data with Samsung Health Data SDK

suspend fun readTodayExercise(healthDataStore: HealthDataStore) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val readRequest = DataTypes.EXERCISE.readDataRequestBuilder
        .setLocalTimeFilter(LocalTimeFilter.of(startTime, endTime))
        .build()

    try {
        val readResult = healthDataStore.readData(readRequest)
        val dataPoints = readResult.dataList

        if (dataPoints.isEmpty()) {
            Log.i(MainActivity.APP_TAG, "No exercises today")
            return
        }

        dataPoints.forEach { dataPoint ->
            val exerciseType = dataPoint.getValue(DataType.ExerciseType.EXERCISE_TYPE)
            val sessions = dataPoint.getValue(DataType.ExerciseType.SESSIONS)

            sessions?.forEach { session ->
                val exerciseSessionType = session.exerciseType
                val exerciseSessionDuration = session.duration
                val exerciseSessionCalories = session.calories
                Log.i(
                    MainActivity.APP_TAG,
                    "Exercise type: $exerciseType, session type: $exerciseSessionType, duration: $exerciseSessionDuration, calories: $exerciseSessionCalories"
                )
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Example code for writing exercise data when using Samsung Health SDK for Android is as follows.

Writing running exercise data with Samsung Health SDK for Android

fun insertRunningExercise(healthDataStore: HealthDataStore) {
    val fiveMinutesAsSeconds = 300L
    val exerciseType = 1002
    val calories = 73f
    val distance = 1000f
    val deviceId = HealthDeviceManager(healthDataStore).localDevice.uuid
    val startTime = Instant.now().minusSeconds(fiveMinutesAsSeconds)
    val endTime = Instant.now()
    val timeOffset = TimeZone.getDefault().getOffset(endTime.toEpochMilli()).toLong()
    val duration = Duration.between(startTime, endTime)
    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val liveData = createLiveData(
        listOf(
            ExerciseLiveData(
                start_time = startTime.toEpochMilli(),
                heart_rate = 144f,
                speed = 1.6f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(30).toEpochMilli(),
                heart_rate = 146f,
                speed = 1.8f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(60).toEpochMilli(),
                heart_rate = 146f,
                speed = 1.9f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(90).toEpochMilli(),
                heart_rate = 152f,
                speed = 2f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(120).toEpochMilli(),
                heart_rate = 154f,
                speed = 2.1f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(150).toEpochMilli(),
                heart_rate = 161f,
                speed = 2.2f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(180).toEpochMilli(),
                heart_rate = 159f,
                speed = 2.1f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(210).toEpochMilli(),
                heart_rate = 160f,
                speed = 2.2f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(240).toEpochMilli(),
                heart_rate = 159f,
                speed = 2.1f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(270).toEpochMilli(),
                heart_rate = 161f,
                speed = 2.2f
            ),
            ExerciseLiveData(
                start_time = startTime.plusSeconds(300).toEpochMilli(),
                heart_rate = 160f,
                speed = 2f
            )
        )
    )

    val healthData = HealthData().apply {
        sourceDevice = deviceId
        putLong(Exercise.START_TIME, startTime.toEpochMilli())
        putLong(Exercise.END_TIME, endTime.toEpochMilli())
        putLong(Exercise.TIME_OFFSET, timeOffset)
        putInt(Exercise.EXERCISE_TYPE, exerciseType)
        putLong(Exercise.DURATION, duration.toMillis())
        putFloat(Exercise.CALORIE, calories)
        putFloat(Exercise.DISTANCE, distance)
        putBlob(Exercise.LIVE_DATA, liveData)
    }

    val insertRequest = HealthDataResolver.InsertRequest.Builder()
        .setDataType(Exercise.HEALTH_DATA_TYPE)
        .build()

    insertRequest.addHealthData(healthData)

    try {
        val result = healthDataResolver.insert(insertRequest).await()

        if (result.status == STATUS_SUCCESSFUL) {
            Log.i(
                MainActivity.APP_TAG,
                "Inserted running exercise. Count of data: ${result.count}"
            )
        } else {
            Log.i(MainActivity.APP_TAG, "Inserting failed")
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

private fun createLiveData(liveDataList: List<ExerciseLiveData>): ByteArray {
    val zip = HealthDataUtil.getJsonBlob(liveDataList)

    return zip
}

data class ExerciseLiveData(
    val start_time: Long,
    val heart_rate: Float,
    val speed: Float
)

Example code for writing exercise data when using Samsung Health Data SDK is as follows. One exercise session of exercise data is writable.

Writing running exercise data with Samsung Health Data SDK

suspend fun insertRunningExercise(healthDataStore: HealthDataStore) {
    val fiveMinutesAsSeconds = 300L
    val calories = 73f
    val distance = 1000f
    val startTime = Instant.now().minusSeconds(fiveMinutesAsSeconds)
    val endTime = Instant.now()
    val duration = Duration.between(startTime, endTime)

    val exerciseLog = listOf(
        ExerciseLog.of(
            timestamp = startTime,
            heartRate = 144f,
            speed = 1.6f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(30),
            heartRate = 146f,
            speed = 1.8f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(60),
            heartRate = 146f,
            speed = 1.9f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(90),
            heartRate = 152f,
            speed = 2f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(120),
            heartRate = 154f,
            speed = 2.1f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(150),
            heartRate = 161f,
            speed = 2.2f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(180),
            heartRate = 159f,
            speed = 2.1f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(210),
            heartRate = 160f,
            speed = 2.2f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(240),
            heartRate = 159f,
            speed = 2.1f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(270),
            heartRate = 161f,
            speed = 2.2f,
            cadence = null,
            count = null,
            power = null
        ),
        ExerciseLog.of(
            timestamp = startTime.plusSeconds(300),
            heartRate = 160f,
            speed = 2f,
            cadence = null,
            count = null,
            power = null
        )
    )

    try {
        val session = ExerciseSession.builder()
            .setStartTime(startTime)
            .setEndTime(endTime)
            .setExerciseType(DataType.ExerciseType.PredefinedExerciseType.RUNNING)
            .setDuration(duration)
            .setCalories(calories)
            .setDistance(distance)
            .setLog(exerciseLog)
            .build()

        val healthDataPoint = HealthDataPoint.builder()
            .setStartTime(startTime)
            .setEndTime(endTime)
            .addFieldData(
                DataType.ExerciseType.EXERCISE_TYPE,
                DataType.ExerciseType.PredefinedExerciseType.RUNNING
            )
            .addFieldData(DataType.ExerciseType.SESSIONS, listOf(session))
            .build()

        val insertRequest = DataTypes.EXERCISE.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertRequest)
        Log.i(MainActivity.APP_TAG, "Inserted running exercise")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Floors Climbed

Floors climbed data is one of the activity health data types. It is displayed in the Activity Tracker in the Samsung Health app.

The corresponding floors climbed data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.FloorsClimbed

FloorsClimbedType

To read today's floors climbed data when using Samsung Health SDK for Android, the following example code can be used.

Reading floors climbed data with Samsung Health SDK for Android

fun readTodayFloorsClimbed(healthDataStore: HealthDataStore) {
    val startTime = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()
    val endTime =
        LocalDate.now().plusDays(1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()

    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val readRequest = HealthDataResolver.ReadRequest.Builder()
        .setDataType(FloorsClimbed.HEALTH_DATA_TYPE)
        .setLocalTimeRange(
            FloorsClimbed.START_TIME,
            FloorsClimbed.TIME_OFFSET,
            startTime,
            endTime
        )
        .build()

    try {
        healthDataResolver.read(readRequest).setResultListener { result ->
            try {
                val iterator = result.iterator()

                if (iterator.hasNext()) {
                    val healthData = iterator.next()
                    val totalCount = healthData.getFloat(FloorsClimbed.FLOOR)
                    Log.i(MainActivity.APP_TAG, "Today floors climbed: $totalCount")
                } else {
                    Log.i(MainActivity.APP_TAG, "Today floors climbed: 0")
                }
            } finally {
                result.close()
            }
        }
    } catch (exception: Exception) {
        exception.message?.let { Log.i(MainActivity.APP_TAG, it) }
    }
}

When using Samsung Health Data SDK to read today's floors climbed data is as follows.

Reading floors climbed data with Samsung Health Data SDK

suspend fun readTodayFloorsClimbed(healthDataStore: HealthDataStore) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val readRequest = DataType.FloorsClimbedType.TOTAL.requestBuilder
        .setLocalTimeFilter(LocalTimeFilter.of(startTime, endTime))
        .build()

    try {
        val readResult = healthDataStore.aggregateData(readRequest)
        val data = readResult.dataList
        val totalCount = if (data.isNotEmpty()) data.first().value else 0
        Log.i(MainActivity.APP_TAG, "Today floors climbed: $totalCount")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

To write floors climbed data when using Samsung Health SDK for Android, the following example code can be used.

Writing floors climbed data with Samsung Health SDK for Android

fun insertTodayFloorsClimbed(healthDataStore: HealthDataStore) {
    val oneMinuteAsSeconds = 60L
    val floor = 2f
    val deviceId = HealthDeviceManager(healthDataStore).localDevice.uuid
    val startTime = Instant.now().minusSeconds(oneMinuteAsSeconds).toEpochMilli()
    val endTime = Instant.now().toEpochMilli()
    val timeOffset = TimeZone.getDefault().getOffset(endTime).toLong()
    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val healthData = HealthData().apply {
        sourceDevice = deviceId
        putLong(FloorsClimbed.START_TIME, startTime)
        putLong(FloorsClimbed.END_TIME, endTime)
        putLong(FloorsClimbed.TIME_OFFSET, timeOffset)
        putFloat(FloorsClimbed.FLOOR, floor)
    }

    val insertRequest = HealthDataResolver.InsertRequest.Builder()
        .setDataType(FloorsClimbed.HEALTH_DATA_TYPE)
        .build()

    insertRequest.addHealthData(healthData)

    try {
        val result = healthDataResolver.insert(insertRequest).await()

        if (result.status == STATUS_SUCCESSFUL) {
            Log.i(
                MainActivity.APP_TAG,
                "Inserted floor climbed. Count of data: ${result.count}"
            )
        } else {
            Log.i(MainActivity.APP_TAG, "Inserting failed")
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to write today's floors climbed data is as follows.

Writing floors climbed data with Samsung Health Data SDK

suspend fun insertTodayFloorClimbed(healthDataStore: HealthDataStore) {
    val oneMinuteAsSeconds = 60L
    val floor = 2f
    val startTime = Instant.now().minusSeconds(oneMinuteAsSeconds)
    val endTime = Instant.now()

    try {
        val healthDataPoint = HealthDataPoint.builder()
            .setStartTime(startTime)
            .setEndTime(endTime)
            .addFieldData(DataType.FloorsClimbedType.FLOOR, floor)
            .build()

        val insertRequest = DataTypes.FLOORS_CLIMBED.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertRequest)
        Log.i(MainActivity.APP_TAG, "Inserted floor climbed")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Nutrition

The Samsung Health app provides a Food Tracker that allows users to record and manage their eating data for each meal type, such as breakfast, lunch, and dinner.

The corresponding nutrition data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.Nutrition

NutritionType

Here is an example code to read today's nutrition data when using Samsung Health SDK for Android.

Reading nutrition data with Samsung Health SDK for Android

fun readTodayNutrition(healthDataStore: HealthDataStore) {
    val startTime = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()
    val endTime =
        LocalDate.now().plusDays(1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()

    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val nutritionRequest = HealthDataResolver.ReadRequest.Builder()
        .setDataType(Nutrition.HEALTH_DATA_TYPE)
        .setLocalTimeRange(Nutrition.START_TIME, Nutrition.TIME_OFFSET, startTime, endTime)
        .build()

    try {
        healthDataResolver.read(nutritionRequest).setResultListener { result ->
            try {
                val iterator = result.iterator()

                iterator.forEach { healthData ->
                    val title = healthData.getString(Nutrition.TITLE)
                    val mealType = healthData.getInt(Nutrition.MEAL_TYPE)
                    val calories = healthData.getFloat(Nutrition.CALORIE)
                    Log.i(MainActivity.APP_TAG, "Today nutrition: $title, $mealType, 
                        $calories")
                }
            } finally {
                result.close()
            }
        }
    } catch (exception: Exception) {
        exception.message?.let { Log.i(MainActivity.APP_TAG, it) }
    }
}

When using Samsung Health Data SDK to read today's nutrition data is as follows.

Reading nutrition data with Samsung Health Data SDK
suspend fun readTodayNutrition(healthDataStore: HealthDataStore) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val readRequest = DataTypes.NUTRITION.readDataRequestBuilder
        .setLocalTimeFilter(LocalTimeFilter.of(startTime, endTime))
        .build()

    try {
        val readResult = healthDataStore.readData(readRequest)

        if (readResult.dataList.isEmpty()) {
            Log.i(MainActivity.APP_TAG, "No nutrition today")
            return
        }

        readResult.dataList.forEach { healthData ->
            val title = healthData.getValue(DataType.NutritionType.TITLE)
            val mealType = healthData.getValue(DataType.NutritionType.MEAL_TYPE)
            val calories = healthData.getValue(DataType.NutritionType.CALORIES)
            Log.i(MainActivity.APP_TAG, "Today nutrition: $title, $mealType, $calories")
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Here is an example code to write nutrition data when using Samsung Health SDK for Android.

Writing nutrition data with Samsung Health SDK for Android

fun insertNutrition(healthDataStore: HealthDataStore) {

    val myDevice = HealthDeviceManager(healthDataStore)

    val mealTitle = "Toast and coffee"
    val calories = 66f
    val totalFat = 0.8f
    val saturatedFat = 0.1f
    val protein = 2.1f
    val carbohydrate = 11.9f
    val totalSugars = 1f
    val dietaryFiber = 0.6f
    val sodium = 135f
    val calcium = 40.3f
    val iron = 0.78f
    val potassium = 140f
    //for females, age 19 - 50, according to https://nap.nationalacademies.org/catalog/11537/dietary-reference-intakes-the-essential-guide-to-nutrient-requirements
    val referenceIndexForIronInMilligrams = 8.1f
    // for age 19-50, refer to the link above.
    val referenceIndexForCalciumInMilligrams = 1000f

    val startTime = Instant.now().toEpochMilli()
    val timeOffset = TimeZone.getDefault().getOffset(startTime).toLong()

    val data = HealthData().apply {
        sourceDevice = myDevice.localDevice.uuid
        putLong(HealthConstants.Nutrition.START_TIME, startTime);
        putLong(HealthConstants.Nutrition.TIME_OFFSET, timeOffset);
        putInt(HealthConstants.Nutrition.MEAL_TYPE, MEAL_TYPE_BREAKFAST)
        putString(HealthConstants.Nutrition.TITLE, mealTitle)
        putFloat(HealthConstants.Nutrition.CALORIE, calories)
        putFloat(HealthConstants.Nutrition.TOTAL_FAT, totalFat)
        putFloat(HealthConstants.Nutrition.SATURATED_FAT, saturatedFat)
        putFloat(HealthConstants.Nutrition.PROTEIN, protein)
        putFloat(HealthConstants.Nutrition.CARBOHYDRATE, carbohydrate)
        putFloat(HealthConstants.Nutrition.SUGAR, totalSugars)
        putFloat(HealthConstants.Nutrition.DIETARY_FIBER, dietaryFiber)
        putFloat(HealthConstants.Nutrition.SODIUM, sodium)
        putFloat(HealthConstants.Nutrition.POTASSIUM, potassium)
        val calciumAsPercentOfReferenceIntake =
            calcium / referenceIndexForCalciumInMilligrams * 100
        val ironInPercentOfReferenceIntake= iron / referenceIndexForIronInMilligrams * 100
        putFloat(HealthConstants.Nutrition.CALCIUM, calciumAsPercentOfReferenceIntake)
        putFloat(HealthConstants.Nutrition.IRON, ironInPercentOfReferenceIntake)
    }
    val insertRequest = HealthDataResolver.InsertRequest.Builder()
        .setDataType(HealthConstants.Nutrition.HEALTH_DATA_TYPE)
        .build()
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    try {
        insertRequest.addHealthData(data)
        val insertResult = healthDataResolver.insert(insertRequest).await()
        Log.i(TAG, "insertNutrition status: ${insertResult.status}")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to write nutrition data is as follows.

Writing nutrition data with Samsung Health Data SDK

suspend fun insertNutrition(healthDataStore: HealthDataStore) {

    val startTime = LocalDateTime.now()
    val mealTitle = "Toast and coffee"
    val calories = 66f
    val totalFat = 0.8f
    val saturatedFat = 0.1f
    val protein = 2.1f
    val carbohydrate = 11.9f
    val sugar = 1f
    val dietaryFiber = 0.6f
    val sodium = 135f
    val calcium = 40.3f
    val iron = 0.78f
    val potassium = 140f

    try {
        val healthDataPoint = HealthDataPoint.builder()
            .setLocalStartTime(startTime)
            .addFieldData(DataType.NutritionType.MEAL_TYPE, MealType.BREAKFAST)
            .addFieldData(DataType.NutritionType.TITLE, mealTitle)
            .addFieldData(DataType.NutritionType.CALORIES, calories)
            .addFieldData(DataType.NutritionType.TOTAL_FAT, totalFat)
            .addFieldData(DataType.NutritionType.SATURATED_FAT, saturatedFat)
            .addFieldData(DataType.NutritionType.PROTEIN, protein)
            .addFieldData(DataType.NutritionType.CARBOHYDRATE, carbohydrate)
            .addFieldData(DataType.NutritionType.SUGAR, sugar)
            .addFieldData(DataType.NutritionType.DIETARY_FIBER, dietaryFiber)
            .addFieldData(DataType.NutritionType.SODIUM, sodium)
            .addFieldData(DataType.NutritionType.CALCIUM, calcium)
            .addFieldData(DataType.NutritionType.IRON, iron)
            .addFieldData(DataType.NutritionType.POTASSIUM, potassium)
            .build()

        val insertDataRequest = DataTypes.NUTRITION.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()
        healthDataStore.insertData(insertDataRequest)

    } catch(e: Exception) {
        e.printStackTrace()
    }
}

Water intake

The data types of Samsung Health SDK for Android and Samsung Health Data SDK are as follows.

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.WaterIntake

WaterIntakeType

Example code for reading today's water intake data when using Samsung Health SDK for Android is as follows.

Reading water intake data with Samsung Health SDK for Android

fun readTodayTotalWaterIntake (
    healthDataStore: HealthDataStore
) {
    val startTime = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()
    val endTime = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val waterIntakeId = "water_intake_sum"
    val aggregateRequest = HealthDataResolver.AggregateRequest.Builder()
        .addFunction(
            HealthDataResolver.AggregateRequest.AggregateFunction.SUM,
            HealthConstants.WaterIntake.AMOUNT,
            waterIntakeId
        )
        .setLocalTimeRange(
            HealthConstants.WaterIntake.START_TIME,
            HealthConstants.WaterIntake.TIME_OFFSET, startTime, endTime
        )
        .setDataType(HealthConstants.WaterIntake.HEALTH_DATA_TYPE).build()
    try {
        healthDataResolver.aggregate(aggregateRequest).setResultListener { result ->
            try {
                result?.forEach { healthData ->
                    val waterIntakeSum = healthData.getFloat(waterIntakeId)
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to read today's water intake data is as follows.

Reading water intake data with Samsung Health Data SDK

suspend fun readTodayTotalWaterIntake(
    healthDataStore: com.samsung.android.sdk.health.data.HealthDataStore
) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val localTimeFilter = LocalTimeFilter.of(startTime, endTime)
    val readRequest = DataType.WaterIntakeType.TOTAL.requestBuilder
        .setLocalTimeFilter(localTimeFilter)
        .build()
    try {
        val result = healthDataStore.aggregateData(readRequest)
        result.dataList.lastOrNull()?.let { dataPoint ->
            val waterIntake = dataPoint.value
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Example code for writing water intake data when using Samsung Health SDK for Android is as follows.

Writing water intake data with Samsung Health SDK for Android

fun insertWaterIntake(healthDataStore: HealthDataStore) {

    val myDevice = HealthDeviceManager(healthDataStore)
    val waterAmountInMilliliters = 250f
    val unitAmount = 250f

    val startTime = Instant.now().toEpochMilli()
    val timeOffset = TimeZone.getDefault().getOffset(startTime).toLong()

    val data = HealthData().apply {
        sourceDevice = myDevice.localDevice.uuid
        putLong(HealthConstants.WaterIntake.START_TIME, startTime);
        putLong(HealthConstants.WaterIntake.TIME_OFFSET, timeOffset);
        putFloat(HealthConstants.WaterIntake.AMOUNT, waterAmountInMilliliters)
        putFloat(HealthConstants.WaterIntake.UNIT_AMOUNT, unitAmount)
    }
    val insertRequest = HealthDataResolver.InsertRequest.Builder()
        .setDataType(HealthConstants.WaterIntake.HEALTH_DATA_TYPE)
        .build()
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    try {
        insertRequest.addHealthData(data)
        val insertResult = healthDataResolver.insert(insertRequest).await()
        Log.i(TAG, "insertWaterIntake status: ${insertResult.status}")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to write water intake data is as follows.

Writing water intake data with Samsung Health Data SDK

suspend fun insertWaterIntake(healthDataStore: HealthDataStore) {
    val startTime = LocalDateTime.now()
    val waterAmountInMilliliters = 250f

    try {
        val healthDataPoint = HealthDataPoint.builder()
            .setLocalStartTime(startTime)
            .addFieldData(DataType.WaterIntakeType.AMOUNT, waterAmountInMilliliters)
            .build()

        val insertDataRequest = DataTypes.WATER_INTAKE.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()
        healthDataStore.insertData(insertDataRequest)
    } catch(e: Exception) {
        e.printStackTrace()
    }
}

Sleep and sleep stage

The data types of Samsung Health SDK for Android and Samsung Health Data SDK are as follows.

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.Sleep
HealthConstants.SleepStage

SleepType

Code for reading the last night's sleep data when using Samsung Health SDK for Android is as follows.

Reading the last night's sleep data with Samsung Health SDK for Android

fun readLastSleep(
    healthDataStore: HealthDataStore
) {
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val resultCount = 1
    val resultOffset = 0
    val request: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.Sleep.HEALTH_DATA_TYPE)
            .setSort(HealthConstants.Sleep.START_TIME, SortOrder.DESC)
            .setResultCount(resultOffset, resultCount)
            .build()
    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                result.lastOrNull()?.let { healthData ->
                    val sleepId = healthData.getString(HealthConstants.Sleep.UUID)
                    val sleepStartTime =
                        Instant.ofEpochMilli(healthData.getLong(HealthConstants.Sleep.START_TIME))
                    val sleepEndTime =
                        Instant.ofEpochMilli(healthData.getLong(HealthConstants.Sleep.END_TIME))
                    readSleepStagesForSleepId(healthDataStore, sleepId)
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

fun readSleepStagesForSleepId(
    healthDataStore: HealthDataStore,
    sleepId: String
) {
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val request: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.SleepStage.HEALTH_DATA_TYPE)
            .setFilter(Filter.eq(HealthConstants.SleepStage.SLEEP_ID, sleepId))
            .build()
    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                result?.forEach { sleepStageData ->
                    val sleepStageName =
                        sleepStageNameById(sleepStageData.getInt(HealthConstants.SleepStage.STAGE))
                    val sleepStageStartTime =
                        Instant.ofEpochMilli(sleepStageData.getLong(HealthConstants.SleepStage.START_TIME))
                    val sleepStageEndTime =
                        Instant.ofEpochMilli(sleepStageData.getLong(HealthConstants.SleepStage.END_TIME))
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

fun sleepStageNameById(id: Int): String {
    return when (id) {
        HealthConstants.SleepStage.STAGE_AWAKE -> "AWAKE"
        HealthConstants.SleepStage.STAGE_DEEP -> "DEEP"
        HealthConstants.SleepStage.STAGE_LIGHT -> "LIGHT"
        HealthConstants.SleepStage.STAGE_REM -> "REM"
        else -> ""
    }
}

When using Samsung Health Data SDK to read the last night's sleep data is as follows.

Reading the last night's sleep data with Samsung Health Data SDK

  suspend fun readSleepTotalDuration(
    healthDataStore: HealthDataStore
) {
    val daysBackOffset = 400L
    val startTime =
        LocalDate.now()
            .minusDays(daysBackOffset)
    val endTime = LocalDate.now()
    val localDateFilter = LocalDateFilter.of(startTime, endTime)
    val request = DataType.SleepType.TOTAL_DURATION.requestBuilder
        .setLocalDateFilter(localDateFilter)
        .build()
    try {
        val result = healthDataStore.aggregateData(request)
        result.dataList.forEach { aggregatedData ->
            val startTime = aggregatedData.startTime
            val endTime = aggregatedData.endTime
            val totalDuration = aggregatedData.value
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}


suspend fun readLastSleep(
    healthDataStore: HealthDataStore
) {
    val resultCount = 1
    val readRequest = DataTypes.SLEEP.readDataRequestBuilder
        .setOrdering(Ordering.DESC)
        .setLimit(resultCount)
        .build()
    try {
        val result = healthDataStore.readData(readRequest)
        result.dataList.lastOrNull()?.let { sleepData ->
            val sleepId = sleepData.uid
            val sleepStartTime = sleepData.startTime
            val sleepEndTime = sleepData.endTime
            val sleepSessions = sleepData.getValue(DataType.SleepType.SESSIONS)
            sleepSessions?.forEach { sleepSession ->
                val sessionDuration = sleepSession.duration
                val sessionStartTime = sleepSession.startTime
                val sessionEndTime = sleepSession.endTime
                val sleepStages = sleepSession.stages
                sleepStages?.forEach { sleepStage ->
                    val sleepStageName = sleepStage.stage.name
                    val sleepStageStartTime = sleepStage.startTime
                    val sleepStageEndTime = sleepStage.endTime
                }
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Code for writing sleep data when using Samsung Health SDK for Android is as follows.

Writing the last night's sleep data with Samsung Health SDK for Android

fun insertSleepData(healthDataStore: HealthDataStore) {
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val healthDeviceManager = HealthDeviceManager(healthDataStore)

    val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(Instant.now())
    val startTime = LocalDate.now().minusDays(1).atTime(23, 10).toInstant(zoneOffset)
    val endTime = LocalDate.now().atTime(6, 30).toInstant(zoneOffset)
    val timeOffset = TimeZone.getDefault().getOffset(Instant.now().toEpochMilli())

    val sleepData = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.Sleep.START_TIME, startTime.toEpochMilli())
        putLong(HealthConstants.Sleep.END_TIME, endTime.toEpochMilli())
        putLong(HealthConstants.Sleep.TIME_OFFSET, timeOffset.toLong())
    }

    val insertRequest = InsertRequest.Builder()
        .setDataType(HealthConstants.Sleep.HEALTH_DATA_TYPE)
        .build()
    insertRequest.addHealthData(sleepData)

    try {
        val insertResult = healthDataResolver.insert(insertRequest).await()
        if (insertResult.status != BaseResult.STATUS_SUCCESSFUL) {
            Log.i(
                MainActivity.APP_TAG,
                "Error inserting sleep data. Error code: ${insertResult.status}"
            )
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }

    val resultCount = 1
    val resultOffset = 0
    val readRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.Sleep.HEALTH_DATA_TYPE)
            .setSort(HealthConstants.Sleep.UPDATE_TIME, SortOrder.DESC)
            .setResultCount(resultOffset, resultCount)
            .build()

    try {
        val readResult = healthDataResolver.read(readRequest).await()
        val sleepId = readResult.last().getString(HealthConstants.Sleep.UUID)
        writeSleepStages(healthDataStore, sleepId)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

private fun writeSleepStages(healthDataStore: HealthDataStore, sleepId: String) {
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val healthDeviceManager = HealthDeviceManager(healthDataStore)

    val startDate = LocalDate.now().minusDays(1)
    val endDate = LocalDate.now()
    val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(Instant.now())
    val timeOffset = TimeZone.getDefault().getOffset(Instant.now().toEpochMilli())
    val sleepStages = mutableListOf<HealthData>()
    var sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            startDate.atTime(23, 10).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            startDate.atTime(23, 35).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_LIGHT)
    }
    sleepStages.add(sleepStage)

    sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            startDate.atTime(23, 35).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            endDate.atTime(1, 50).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_DEEP)
    }
    sleepStages.add(sleepStage)
    sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            endDate.atTime(1, 50).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            endDate.atTime(2, 20).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_REM)
    }
    sleepStages.add(sleepStage)
    sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            endDate.atTime(2, 20).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            endDate.atTime(2, 55).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_LIGHT)
    }
    sleepStages.add(sleepStage)
    sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            endDate.atTime(2, 55).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            endDate.atTime(3, 10).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_AWAKE)
    }
    sleepStages.add(sleepStage)
    sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            endDate.atTime(3, 10).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            endDate.atTime(4, 30).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_DEEP)
    }
    sleepStages.add(sleepStage)
    sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            endDate.atTime(4, 30).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            endDate.atTime(5, 10).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_REM)
    }
    sleepStages.add(sleepStage)
    sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            endDate.atTime(5, 10).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            endDate.atTime(6, 20).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_LIGHT)
    }
    sleepStages.add(sleepStage)
    sleepStage = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.SleepStage.TIME_OFFSET, timeOffset.toLong())
        putString(HealthConstants.SleepStage.SLEEP_ID, sleepId)
        putLong(
            HealthConstants.SleepStage.START_TIME,
            endDate.atTime(6, 20).toInstant(zoneOffset).toEpochMilli()
        )
        putLong(
            HealthConstants.SleepStage.END_TIME,
            endDate.atTime(6, 30).toInstant(zoneOffset).toEpochMilli()
        )
        putInt(HealthConstants.SleepStage.STAGE, HealthConstants.SleepStage.STAGE_AWAKE)
    }
    sleepStages.add(sleepStage)

    val insertRequest = InsertRequest.Builder()
        .setDataType(HealthConstants.SleepStage.HEALTH_DATA_TYPE)
        .build()
    insertRequest.addHealthData(sleepStages)

    try {
        val insertResult = healthDataResolver.insert(insertRequest).await()
        if (insertResult.status != BaseResult.STATUS_SUCCESSFUL) {
            Log.i(
                MainActivity.APP_TAG,
                "Error inserting stages data. Error code: ${insertResult.status}"
            )
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to write sleep data is as follows.

Writing the last night's sleep data with Samsung Health Data SDK

suspend fun insertSleepData(healthDataStore: HealthDataStore) {
    val startDate = LocalDate.now().minusDays(1)
    val endDate = LocalDate.now()
    val startTime = startDate.atTime(23, 10)
    val endTime = endDate.atTime(6, 30)
    val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(Instant.now())
    val duration = Duration.between(startTime, endTime)


    val sleepStageList = listOf(
        SleepSession.SleepStage.of(
            startDate.atTime(23, 10).toInstant(zoneOffset),
            startDate.atTime(23, 35).toInstant(zoneOffset),
            DataType.SleepType.StageType.LIGHT
        ),
        SleepSession.SleepStage.of(
            startDate.atTime(23, 35).toInstant(zoneOffset),
            endDate.atTime(1, 50).toInstant(zoneOffset),
            DataType.SleepType.StageType.DEEP
        ),
        SleepSession.SleepStage.of(
            endDate.atTime(1, 50).toInstant(zoneOffset),
            endDate.atTime(2, 20).toInstant(zoneOffset),
            DataType.SleepType.StageType.REM
        ),
        SleepSession.SleepStage.of(
            endDate.atTime(2, 20).toInstant(zoneOffset),
            endDate.atTime(2, 55).toInstant(zoneOffset),
            DataType.SleepType.StageType.LIGHT
        ),
        SleepSession.SleepStage.of(
            endDate.atTime(2, 55).toInstant(zoneOffset),
            endDate.atTime(3, 10).toInstant(zoneOffset),
            DataType.SleepType.StageType.AWAKE
        ),
        SleepSession.SleepStage.of(
            endDate.atTime(3, 10).toInstant(zoneOffset),
            endDate.atTime(4, 30).toInstant(zoneOffset),
            DataType.SleepType.StageType.DEEP
        ),
        SleepSession.SleepStage.of(
            endDate.atTime(4, 30).toInstant(zoneOffset),
            endDate.atTime(5, 10).toInstant(zoneOffset),
            DataType.SleepType.StageType.REM
        ),
        SleepSession.SleepStage.of(
            endDate.atTime(5, 10).toInstant(zoneOffset),
            endDate.atTime(6, 20).toInstant(zoneOffset),
            DataType.SleepType.StageType.LIGHT
        ),
        SleepSession.SleepStage.of(
            endDate.atTime(6, 20).toInstant(zoneOffset),
            endDate.atTime(6, 30).toInstant(zoneOffset),
            DataType.SleepType.StageType.AWAKE
        )
    )

    val sleepSession = SleepSession.of(
        startTime.toInstant(zoneOffset),
        endTime.toInstant(zoneOffset),
        duration,
        sleepStageList
    )
    try {
        val healthDataPoint = HealthDataPoint.builder()
            .setLocalStartTime(startTime)
            .setLocalEndTime(endTime)
            .addFieldData(
                DataType.SleepType.DURATION,
                duration
            )
            .addFieldData(DataType.SleepType.SESSIONS, listOf(sleepSession))
            .build()

        val insertDataRequest = DataTypes.SLEEP.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertDataRequest)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Weight

The corresponding weight data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.Weight

BodyCompositionType

To read the latest weight data when using Samsung Health SDK for Android, the following example code can be used.

Reading the last weight data with Samsung Health SDK for Android

fun readLatestWeight(
    healthDataStore: HealthDataStore
) {
    val resultCount = 1
    val resultOffset = 0
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val request: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.Weight.HEALTH_DATA_TYPE)
            .setSort(HealthConstants.OxygenSaturation.START_TIME, SortOrder.DESC)
            .setResultCount(resultOffset, resultCount)
            .build()
    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                result.lastOrNull()?.let { healthData ->
                    val measurementStartTime =
                        Instant.ofEpochMilli(healthData.getLong(HealthConstants.Weight.START_TIME))
                    val weight = healthData.getFloat(HealthConstants.Weight.WEIGHT)
                    val bodyFat = healthData.getFloat(HealthConstants.Weight.BODY_FAT)
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to read the latest weight data is as follows.

Reading the last weight data with Samsung Health Data SDK

suspend fun readLatestWeight(
    healthDataStore: HealthDataStore
) {
    val resultCount = 1
    val readRequest = DataTypes.BODY_COMPOSITION.readDataRequestBuilder
        .setOrdering(Ordering.DESC)
        .setLimit(resultCount)
        .build()
    try {
        val result = healthDataStore.readData(readRequest)
        result.dataList.lastOrNull()?.let { dataPoint ->
            val weight = dataPoint.getValue(DataType.BodyCompositionType.WEIGHT)
            val bodyFat = dataPoint.getValue(DataType.BodyCompositionType.BODY_FAT)
            val measurementStartTime = dataPoint.startTime
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Here is an example code to write weight data when using Samsung Health SDK for Android.

Writing weight data with Samsung Health SDK for Android

fun insertWeightData(
    healthDataStore: HealthDataStore
) {
    val weight = 75F
    val zoneId = ZoneOffset.systemDefault()
    val startTime = LocalDate.now().atTime(9, 0).atZone(zoneId).toInstant().toEpochMilli()
    val timeOffset = TimeZone.getDefault().getOffset(startTime).toLong()
    val mHealthDataResolver =
        HealthDataResolver(healthDataStore, Handler(Looper.getMainLooper()))
    val healthDeviceManager = HealthDeviceManager(healthDataStore)
    val data = HealthData().apply {
        putLong(HealthConstants.Weight.START_TIME, startTime)
        putLong(HealthConstants.Weight.TIME_OFFSET, timeOffset)
        putFloat(HealthConstants.Weight.WEIGHT, weight)
        // Register local device as the source of data
        sourceDevice = healthDeviceManager.localDevice.uuid
    }

    try {
        val insertRequest = InsertRequest.Builder()
            .setDataType(HealthConstants.Weight.HEALTH_DATA_TYPE)
            .build()
        insertRequest.addHealthData(data)

        val result = mHealthDataResolver.insert(insertRequest).await()
        Log.i(MainActivity.APP_TAG, "insert result status: ${result.status}")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Writing weight data with Samsung Health Data SDK

suspend fun insertWeightData(
    healthDataStore: HealthDataStore
) {
    val weight = 75F
    val localDateTime = LocalDate.now().atTime(9, 0)
    val zoneId = ZoneOffset.systemDefault()
    val zoneOffset = zoneId.rules.getOffset(localDateTime)

    try {
        val healthDataPoint = HealthDataPoint.builder()
            .addFieldData(DataType.BodyCompositionType.WEIGHT, weight)
            .setLocalStartTime(localDateTime, zoneOffset)
            .build()
        val insertRequest = DataTypes.BODY_COMPOSITION.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertRequest)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Heart rate

The corresponding heart rate data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.HeartRate

HeartRateType

Example code for reading today's heart rate data when using Samsung Health SDK for Android is as follows.

Reading today's heart rate data with Samsung Health SDK for Android

class ReadHeartRate {

    fun readTodayHeartRate(
        healthDataStore: HealthDataStore
    ) {
        val startTime = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()
        val endTime = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()
        val handler = Handler(Looper.getMainLooper())
        val healthDataResolver = HealthDataResolver(healthDataStore, handler)
        val request: HealthDataResolver.ReadRequest =
            HealthDataResolver.ReadRequest.Builder()
                .setDataType(HealthConstants.HeartRate.HEALTH_DATA_TYPE)
                .setLocalTimeRange(
                    HealthConstants.HeartRate.START_TIME,
                    HealthConstants.HeartRate.TIME_OFFSET, startTime, endTime
                ).build()
        try {
            healthDataResolver.read(request).setResultListener { result ->
                try {
                    result?.forEach { healthData ->
                        val heartRate = healthData.getFloat(HealthConstants.HeartRate.HEART_RATE)
                        val measurementStartTime =
                            Instant.ofEpochMilli(healthData.getLong(HealthConstants.HeartRate.START_TIME))
                        val measurementEndTime =
                            Instant.ofEpochMilli(healthData.getLong(HealthConstants.HeartRate.END_TIME))
                        val binningData = healthData.getBlob(HealthConstants.HeartRate.BINNING_DATA)
                        val liveDataList = HealthDataUtil.getStructuredDataList(
                            binningData,
                            HeartRateLiveData::class.java
                        )
                        liveDataList.forEach { liveDataPoint ->
                            val heartRate = liveDataPoint.heart_rate
                            val startTime = Instant.ofEpochMilli(liveDataPoint.start_time)
                        }
                    }
                } finally {
                    result.close()
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

data class HeartRateLiveData(
    val heart_rate: Float,
    val heart_rate_min: Float,
    val heart_rate_max: Float,
    val start_time: Long,
    val end_time: Long
)

When using Samsung Health Data SDK to read today's heart rate data is as follows.

Reading today's heart rate data with Samsung Health Data SDK

suspend fun readTodayHeartRate (
    healthDataStore: HealthDataStore
) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val localTimeFilter = LocalTimeFilter.of(startTime, endTime)
    val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder
        .setLocalTimeFilter(localTimeFilter)
        .build()
    try {
        val result = healthDataStore.readData(readRequest)
        result.dataList.forEach { dataPoint ->
            val startTime = dataPoint.startTime
            val endTime = dataPoint.endTime
            val heartRate = dataPoint.getValue(DataType.HeartRateType.HEART_RATE)
            val heartRateSeriesData = dataPoint.getValue(DataType.HeartRateType.SERIES_DATA)
            heartRateSeriesData?.forEach { seriesData ->
                val startTime = seriesData.startTime
                val heartRate = seriesData.heartRate
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

To write heart rate data when using Samsung Health SDK for Android, the following example code can be used.

Writing heart rate data with Samsung Health SDK for Android

fun insertTodayHeartRate(healthDataStore: HealthDataStore) {
    val tenMinutesAsSeconds = 600L
    val heartRate = 76f
    val heartBeatCount = 1
    val deviceId = HealthDeviceManager(healthDataStore).localDevice.uuid
    val startTime = Instant.now().minusSeconds(tenMinutesAsSeconds).toEpochMilli()
    val endTime = Instant.now().toEpochMilli()
    val timeOffset = TimeZone.getDefault().getOffset(endTime).toLong()
    val healthDataResolver = HealthDataResolver(healthDataStore, null)

    val healthData = HealthData().apply {
        sourceDevice = deviceId
        putLong(HeartRate.START_TIME, startTime)
        putLong(HeartRate.END_TIME, endTime)
        putLong(HeartRate.TIME_OFFSET, timeOffset)
        putFloat(HeartRate.HEART_RATE, heartRate)
        putInt(HeartRate.HEART_BEAT_COUNT, heartBeatCount)
    }

    val insertRequest = HealthDataResolver.InsertRequest.Builder()
        .setDataType(HeartRate.HEALTH_DATA_TYPE)
        .build()

    insertRequest.addHealthData(healthData)

    try {
        val result = healthDataResolver.insert(insertRequest).await()

        if (result.status == STATUS_SUCCESSFUL) {
            Log.i(MainActivity.APP_TAG, "Inserted heart rate. Count of data: ${result.count}")
        } else {
            Log.i(MainActivity.APP_TAG, "Inserting failed")
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to write heart rate data is as follows.

Writing heart rate data with Samsung Health Data SDK

suspend fun insertTodayHeartRate(healthDataStore: HealthDataStore) {
    val tenMinutesAsSeconds = 600L
    val heartRate = 76f
    val startTime = LocalDateTime.now().minusSeconds(tenMinutesAsSeconds)
    val endTime = LocalDateTime.now()

    try {
        val healthDataPoint = HealthDataPoint.builder()
            .setLocalStartTime(startTime)
            .setLocalEndTime(endTime)
            .addFieldData(DataType.HeartRateType.HEART_RATE, heartRate)
            .build()

        val insertRequest = DataTypes.HEART_RATE.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertRequest)
        Log.i(MainActivity.APP_TAG, "Inserted heart rate")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Blood glucose

The corresponding blood glucose data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.BloodGlucose

BloodGlucoseType

Here is an example code to read today's blood glucose data when using Samsung Health SDK for Android.

Reading today's blood glucose data with Samsung Health SDK for Android

fun readTodayBloodGlucose (
    healthDataStore: HealthDataStore
) {
    val startTime = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()
    val endTime = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val request: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.BloodGlucose.HEALTH_DATA_TYPE)
            .setLocalTimeRange(
                HealthConstants.OxygenSaturation.START_TIME,
                HealthConstants.OxygenSaturation.TIME_OFFSET, startTime, endTime
            ).build()
    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                result.forEach { healthData ->
                    val measurementStartTime =
                        Instant.ofEpochMilli(healthData.getLong(HealthConstants.BloodGlucose.START_TIME))
                    val bloodGlucose = healthData.getFloat(HealthConstants.BloodGlucose.GLUCOSE)
                    //Refer to the documentation for MEAL_TYPE, MEASUREMENT_TYPE, SAMPLE_SOURCE_TYPE mapping
                    val mealType = healthData.getInt(HealthConstants.BloodGlucose.MEAL_TYPE)
                    val measurementType =
                        healthData.getInt(HealthConstants.BloodGlucose.MEASUREMENT_TYPE)
                    val sampleSourceType =
                        healthData.getInt(HealthConstants.BloodGlucose.SAMPLE_SOURCE_TYPE)
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to read today's blood glucose data is as follows.

Reading today's blood glucose data with Samsung Health Data SDK

fun readTodayBloodGlucose(
    healthDataStore: HealthDataStore
) {
    val startTime = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()
    val endTime = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val request: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.BloodGlucose.HEALTH_DATA_TYPE)
            .setLocalTimeRange(
                HealthConstants.OxygenSaturation.START_TIME,
                HealthConstants.OxygenSaturation.TIME_OFFSET, startTime, endTime
            ).build()
    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                result.forEach { healthData ->
                    val measurementStartTime =
                        Instant.ofEpochMilli(healthData.getLong(HealthConstants.BloodGlucose.START_TIME))
                    val bloodGlucose = healthData.getFloat(HealthConstants.BloodGlucose.GLUCOSE)
                    //Refer to the documentation for MEAL_TYPE, MEASUREMENT_TYPE, SAMPLE_SOURCE_TYPE mapping
                    val mealType = healthData.getInt(HealthConstants.BloodGlucose.MEAL_TYPE)
                    val measurementType =
                        healthData.getInt(HealthConstants.BloodGlucose.MEASUREMENT_TYPE)
                    val sampleSourceType =
                        healthData.getInt(HealthConstants.BloodGlucose.SAMPLE_SOURCE_TYPE)
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Code for writing sleep data when using Samsung Health SDK for Android is as follows.

Writing blood glucose data with Samsung Health SDK for Android

fun insertBloodGlucoseData(healthDataStore: HealthDataStore) {
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val healthDeviceManager = HealthDeviceManager(healthDataStore)

    val tenMinutesAsSeconds = 600L
    val startTime = Instant.now().minusSeconds(tenMinutesAsSeconds)
    val timeOffset = TimeZone.getDefault().getOffset(startTime.toEpochMilli())
    val glucose = 4.8f

    val bloodGlucoseData = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(
            HealthConstants.BloodPressure.START_TIME, startTime.toEpochMilli()
        )
        putLong(HealthConstants.BloodGlucose.TIME_OFFSET, timeOffset.toLong())
        putFloat(HealthConstants.BloodGlucose.GLUCOSE, glucose)
        putInt(
            HealthConstants.BloodGlucose.MEASUREMENT_TYPE,
            HealthConstants.BloodGlucose.MEASUREMENT_TYPE_WHOLE_BLOOD
        )
        putInt(
            HealthConstants.BloodGlucose.MEAL_TYPE,
            HealthConstants.BloodGlucose.MEAL_TYPE_FASTING
        )
    }

    val insertRequest = InsertRequest.Builder()
        .setDataType(HealthConstants.BloodGlucose.HEALTH_DATA_TYPE)
        .build()
    insertRequest.addHealthData(bloodGlucoseData)

    try {
        val insertResult = healthDataResolver.insert(insertRequest).await()
        if (insertResult.status != BaseResult.STATUS_SUCCESSFUL) {
            Log.i(
                MainActivity.APP_TAG,
                "Error inserting blood glucose data. Error code: ${insertResult.status}"
            )
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Example code for writing blood glucose data when using Samsung Health Data SDK is as follows.

Writing blood glucose data with Samsung Health Data SDK

suspend fun insertBloodGlucoseData(healthDataStore: HealthDataStore) {
    val startTime = LocalDateTime.now().minusMinutes(10)
    val glucose = 4.8f
    try {
        val healthDataPoint = HealthDataPoint.builder()
            .setLocalStartTime(startTime)
            .setLocalEndTime(startTime)
            .addFieldData(DataType.BloodGlucoseType.GLUCOSE_LEVEL, glucose)
            .addFieldData(
                DataType.BloodGlucoseType.MEASUREMENT_TYPE,
                DataType.BloodGlucoseType.MeasurementType.WHOLE_BLOOD
            )
            .addFieldData(
                DataType.BloodGlucoseType.MEAL_STATUS,
                DataType.BloodGlucoseType.MealStatus.FASTING
            )
            .build()

        val insertDataRequest = DataTypes.BLOOD_GLUCOSE.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertDataRequest)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Blood oxygen

The corresponding blood oxygen data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.OxygenSaturationType

BloodOxygenType

Example code for reading the latest blood oxygen data when using Samsung Health SDK for Android is as follows.

Reading the latest blood oxygen data with Samsung Health SDK for Android

fun readLatestBloodOxygen(
    healthDataStore: HealthDataStore
) {
    val resultOffset = 0;
    val resultCount = 1
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val request: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.OxygenSaturation.HEALTH_DATA_TYPE)
            .setSort(HealthConstants.OxygenSaturation.START_TIME, SortOrder.DESC)
            .setResultCount(resultOffset, resultCount)
            .build()
    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                result.lastOrNull()?.let { healthData ->
                    val bloodOxygen = healthData.getFloat(HealthConstants.OxygenSaturation.SPO2)
                    val measurementStartTime =
                        Instant.ofEpochMilli(healthData.getLong(HealthConstants.OxygenSaturation.START_TIME))
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to read the latest blood oxygen data is as follows.

Reading the latest blood oxygen data with Samsung Health Data SDK

suspend fun readLatestBloodOxygen(
    healthDataStore: HealthDataStore
) {
    val resultCount = 1
    val readRequest = DataTypes.BLOOD_OXYGEN.readDataRequestBuilder
        .setOrdering(Ordering.DESC)
        .setLimit(resultCount)
        .build()
    try {
        val result = healthDataStore.readData(readRequest)
        result.dataList.lastOrNull()?.let { dataPoint ->
            val bloodOxygen = dataPoint.getValue(DataType.BloodOxygenType.OXYGEN_SATURATION)
            val measurementStartTime = dataPoint.startTime
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Here is an example code to write blood oxygen data when using Samsung Health SDK for Android.

Writing blood oxygen data with Samsung Health SDK for Android

fun insertBloodOxygenData(
    healthDataStore: HealthDataStore
) {
    val bloodOxygen = 98F
    val tenMinutesAsSeconds = 10L * 60L
    val zoneId = ZoneOffset.systemDefault()
    val time = LocalDateTime.now().minusSeconds(tenMinutesAsSeconds).atZone(zoneId)
        .toInstant().toEpochMilli()
    val timeOffset = TimeZone.getDefault().getOffset(time).toLong()
    val mHealthDataResolver =
        HealthDataResolver(healthDataStore, Handler(Looper.getMainLooper()))
    val healthDeviceManager = HealthDeviceManager(healthDataStore)
    val data = HealthData().apply {
        putLong(HealthConstants.OxygenSaturation.START_TIME, time)
        putLong(HealthConstants.OxygenSaturation.END_TIME, time)
        putLong(HealthConstants.OxygenSaturation.TIME_OFFSET, timeOffset)
        putFloat(HealthConstants.OxygenSaturation.SPO2, bloodOxygen)
        // Register local device as the source of data
        sourceDevice = healthDeviceManager.localDevice.uuid
    }

    try {
        val insertRequest = InsertRequest.Builder()
            .setDataType(HealthConstants.OxygenSaturation.HEALTH_DATA_TYPE)
            .build()
        insertRequest.addHealthData(data)

        val result = mHealthDataResolver.insert(insertRequest).await()
        Log.i(MainActivity.APP_TAG, "insert result status: ${result.status}")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Example code for writing blood oxygen data when using Samsung Health Data SDK is as follows.

Writing blood oxygen data with Samsung Health Data SDK

suspend fun insertBloodOxygenData(
    healthDataStore: HealthDataStore
) {
    val bloodOxygen = 98F
    val tenMinutesAsSeconds = 10L * 60L
    val time = LocalDateTime.now().minusSeconds(tenMinutesAsSeconds)
    val zoneId = ZoneOffset.systemDefault()
    val zoneOffset = zoneId.rules.getOffset(time)

    try {
        val healthDataPoint = HealthDataPoint.builder()
            .addFieldData(DataType.BloodOxygenType.OXYGEN_SATURATION, bloodOxygen)
            .setLocalStartTime(time, zoneOffset)
            .setLocalEndTime(time, zoneOffset)
            .build()
        val insertRequest = DataTypes.BLOOD_OXYGEN.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertRequest)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Blood pressure

The corresponding blood pressure data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.BloodPressure

BloodPressureType

Code for reading the latest blood pressure data when using Samsung Health SDK for Android is as follows.

Reading the latest blood pressure data with Samsung Health SDK for Android

fun readLatestBloodPressure(
    healthDataStore: HealthDataStore
) {
    val resultOffset = 0;
    val resultCount = 1
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val request: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.BloodPressure.HEALTH_DATA_TYPE)
            .setSort(HealthConstants.BloodPressure.START_TIME, SortOrder.DESC)
            .setResultCount(resultOffset, resultCount)
            .build()
    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                result?.lastOrNull()?.let { healthData ->
                    val startTime =
                        Instant.ofEpochMilli(healthData.getLong(HealthConstants.BloodPressure.START_TIME))
                    val systolicPressure =
                        healthData.getFloat(HealthConstants.BloodPressure.SYSTOLIC)
                    val diastolicPressure =
                        healthData.getFloat(HealthConstants.BloodPressure.DIASTOLIC)
                    val mean = healthData.getFloat(HealthConstants.BloodPressure.MEAN)
                    val pulse = healthData.getInt(HealthConstants.BloodPressure.PULSE)
                    val sourcePackageName =
                        healthData.getString(HealthConstants.Common.PACKAGE_NAME)
                    val sourceDeviceID =
                        healthData.getString(HealthConstants.Common.DEVICE_UUID)
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to read the latest blood pressure data is as follows.

Reading the latest blood pressure data with Samsung Health Data SDK

suspend fun readLatestBloodPressure(
    healthDataStore: HealthDataStore
) {
    val resultCount = 1
    val readRequest = DataTypes.BLOOD_PRESSURE.readDataRequestBuilder
        .setOrdering(Ordering.DESC)
        .setLimit(resultCount)
        .build()
    try {
        val result = healthDataStore.readData(readRequest)
        result.dataList.lastOrNull()?.let { dataPoint ->
            val startTime = dataPoint.startTime
            val systolicPressure = dataPoint.getValue(DataType.BloodPressureType.SYSTOLIC)
            val diastolicPressure = dataPoint.getValue(DataType.BloodPressureType.DIASTOLIC)
            val mean = dataPoint.getValue(DataType.BloodPressureType.MEAN)
            val pulse = dataPoint.getValue(DataType.BloodPressureType.PULSE_RATE)
            val sourcePackageName = dataPoint.dataSource?.appId
            val sourceDeviceId = dataPoint.dataSource?.deviceId
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Code for writing blood pressure data when using Samsung Health SDK for Android is as follows.

Writing blood pressure data with Samsung Health SDK for Android

fun insertBloodPressureData(healthDataStore: HealthDataStore) {
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val healthDeviceManager = HealthDeviceManager(healthDataStore)

    val tenMinutesAsSeconds = 600L
    val startTime = Instant.now().minusSeconds(tenMinutesAsSeconds)
    val timeOffset = TimeZone.getDefault().getOffset(startTime.toEpochMilli())
    val systolic = 119f
    val diastolic = 87f
    val mean = 0f

    val bloodPressureData = HealthData().apply {
        sourceDevice = healthDeviceManager.localDevice.uuid
        putLong(HealthConstants.BloodPressure.START_TIME, startTime.toEpochMilli())
        putLong(HealthConstants.BloodPressure.TIME_OFFSET, timeOffset.toLong())
        putFloat(HealthConstants.BloodPressure.SYSTOLIC, systolic)
        putFloat(HealthConstants.BloodPressure.DIASTOLIC, diastolic)
        putFloat(HealthConstants.BloodPressure.MEAN, mean)
    }

    val insertRequest = InsertRequest.Builder()
        .setDataType(HealthConstants.BloodPressure.HEALTH_DATA_TYPE)
        .build()
    insertRequest.addHealthData(bloodPressureData)

    try {
        val insertResult = healthDataResolver.insert(insertRequest).await()
        if (insertResult.status != BaseResult.STATUS_SUCCESSFUL) {
            Log.i(
                MainActivity.APP_TAG,
                "Error inserting blood pressure data. Error code: ${insertResult.status}"
            )
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Example code for writing blood pressure data when using Samsung Health Data SDK is as follows.

Writing blood pressure data with Samsung Health Data SDK

suspend fun insertBloodPressureData(healthDataStore: HealthDataStore) {
    val startTime = LocalDateTime.now().minusMinutes(10)
    val systolic = 119f
    val diastolic = 87f
    val mean = 0f
    try {
        val healthDataPoint = HealthDataPoint.builder()
            .setLocalStartTime(startTime)
            .addFieldData(DataType.BloodPressureType.SYSTOLIC, systolic)
            .addFieldData(DataType.BloodPressureType.DIASTOLIC, diastolic)
            .addFieldData(DataType.BloodPressureType.MEAN, mean)
            .build()

        val insertDataRequest = DataTypes.BLOOD_PRESSURE.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertDataRequest)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Body Temperature

The corresponding body temperature data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthConstants.BodyTemperature

BodyTemperatureType

Here is an example of code that reads today's body temperature data when using Samsung Health SDK for Android.

Reading today's body temperature data with Samsung Health SDK for Android

fun readTodayBodyTemperature(
    healthDataStore: HealthDataStore
) {
    val startTime = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli()
    val endTime = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val readRequest: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.BodyTemperature.HEALTH_DATA_TYPE)
            .setLocalTimeRange(
                HealthConstants.BodyTemperature.START_TIME,
                HealthConstants.BodyTemperature.TIME_OFFSET,
                startTime,
                endTime
            ).build()

    try {
        healthDataResolver.read(readRequest).setResultListener { result ->
            try {
                result.lastOrNull()?.let { healthData ->
                    val measurementStartTime =
                        Date(healthData.getLong(HealthConstants.BodyTemperature.START_TIME))
                    val bodyTemperature =
                        healthData.getFloat(HealthConstants.BodyTemperature.TEMPERATURE)
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to read today's body temperature data is as follows.

Reading today's body temperature Samsung Health Data SDK

suspend fun readTodayBodyTemperature(
    healthDataStore: com.samsung.android.sdk.health.data.HealthDataStore
) {
    val startTime = LocalDate.now().atStartOfDay()
    val endTime = LocalDateTime.now()
    val localTimeFilter = LocalTimeFilter.of(startTime, endTime)
    val readRequest = DataTypes.BODY_TEMPERATURE.readDataRequestBuilder
        .setLocalTimeFilter(localTimeFilter)
        .build()

    try {
        val result = healthDataStore.readData(readRequest)
        result.dataList.lastOrNull()?.let { dataPoint ->
            val measurementStartTime = dataPoint.startTime
            val bodyTemperature =
                dataPoint.getValue(DataType.BodyTemperatureType.BODY_TEMPERATURE)
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Example code for writing body temperature data when using Samsung Health SDK for Android is as follows.

Writing body temperature data with Samsung Health SDK for Android

fun insertBodyTemperatureData(
    healthDataStore: HealthDataStore
) {
    val bodyTemperature = 37F
    val tenMinutesAsSeconds = 10L * 60L
    val zoneId = ZoneOffset.systemDefault()
    val startTime = LocalDateTime.now().minusSeconds(tenMinutesAsSeconds).atZone(zoneId)
        .toInstant().toEpochMilli()
    val timeOffset = TimeZone.getDefault().getOffset(startTime).toLong()
    val mHealthDataResolver =
        HealthDataResolver(healthDataStore, Handler(Looper.getMainLooper()))
    val healthDeviceManager = HealthDeviceManager(healthDataStore)
    val data = HealthData().apply {
        putLong(HealthConstants.BodyTemperature.START_TIME, startTime)
        putLong(HealthConstants.BodyTemperature.TIME_OFFSET, timeOffset)
        putFloat(HealthConstants.BodyTemperature.TEMPERATURE, bodyTemperature)
        // Register local device as the source of data
        sourceDevice = healthDeviceManager.localDevice.uuid
    }

    try {
        val insertRequest = InsertRequest.Builder()
            .setDataType(HealthConstants.BodyTemperature.HEALTH_DATA_TYPE)
            .build()
        insertRequest.addHealthData(data)

        val result = mHealthDataResolver.insert(insertRequest).await()
        Log.i(MainActivity.APP_TAG, "insert result status: ${result.status}")
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

When using Samsung Health Data SDK to write body temperature data is as follows.

Writing body temperature data with Samsung Health Data SDK

suspend fun insertBodyTemperatureData(
    healthDataStore: HealthDataStore
) {
    val bodyTemperature = 37F
    val tenMinutesAsSeconds = 10L * 60L
    val time = LocalDateTime.now().minusSeconds(tenMinutesAsSeconds)
    val zoneId = ZoneOffset.systemDefault()
    val zoneOffset = zoneId.rules.getOffset(time)

    try {
        val healthDataPoint = HealthDataPoint.builder()
            .addFieldData(DataType.BodyTemperatureType.BODY_TEMPERATURE, bodyTemperature)
            .setLocalStartTime(time, zoneOffset)
            .setLocalEndTime(time, zoneOffset)
            .build()
        val insertRequest = DataTypes.BODY_TEMPERATURE.insertDataRequestBuilder
            .addData(healthDataPoint)
            .build()

        healthDataStore.insertData(insertRequest)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

User profile

The corresponding user profile data types in Samsung Health SDK for Android and Samsung Health Data SDK are as following:

Samsung Health SDK for Android

Samsung Health Data SDK

HealthUserProfile

UserProfileDataType

Example code for getting user profile data when using Samsung Health SDK for Android is as follows.

Getting user profile data with Samsung Health SDK for Android

fun readUserProfile(
    healthDataStore: HealthDataStore
) {
    val userProfile = HealthUserProfile.getProfile(healthDataStore)
    val gender = genderNameById(userProfile.gender)
    val height = userProfile.height
    val weight = userProfile.weight
}

fun genderNameById(id: Int): String {
    return when (id) {
        HealthUserProfile.GENDER_MALE -> "MALE"
        HealthUserProfile.GENDER_FEMALE -> "FEMALE"
        else -> "UNKNOWN"
    }
}

Example code for getting user profile data when using Samsung Health Data SDK is as follows.

Getting user profile data with Samsung Health Data SDK

suspend fun readUserProfile(
    healthDataStore: HealthDataStore
) {
    val readRequest = DataTypes.USER_PROFILE.readDataRequestBuilder
        .build()
    try {
        val result = healthDataStore.readData(readRequest)
        result.dataList.lastOrNull()?.let { dataPoint ->
            val gender = dataPoint.getValue(DataType.UserProfileDataType.GENDER)
            val height = dataPoint.getValue(DataType.UserProfileDataType.HEIGHT)
            val weight = dataPoint.getValue(DataType.UserProfileDataType.WEIGHT)
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Getting data's source device

Code for getting source device information that provided sleep data when using Samsung Health SDK for Android is as follows.

Getting data's source device information with Samsung Health SDK for Android

fun getSourceDeviceInfoOfSleepData(
    healthDataStore: HealthDataStore
) {
    val resultCount = 1
    val resultOffset = 0
    val handler = Handler(Looper.getMainLooper())
    val healthDataResolver = HealthDataResolver(healthDataStore, handler)
    val request: HealthDataResolver.ReadRequest =
        HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.Sleep.HEALTH_DATA_TYPE)
            .setSort(HealthConstants.Sleep.START_TIME, SortOrder.DESC)
            .setResultCount(resultOffset, resultCount)
            .build()
    try {
        healthDataResolver.read(request).setResultListener { result ->
            try {
                result?.forEach { healthData ->
                    val deviceId = healthData.getString(HealthConstants.Sleep.DEVICE_UUID)
                    val healthDevice =
                        HealthDeviceManager(healthDataStore).getDeviceByUuid(deviceId)
                    val deviceName = healthDevice.customName
                    val deviceType = deviceGroupNameById(healthDevice.group)
                }
            } finally {
                result.close()
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

fun deviceGroupNameById(id: Int): String {
    return when (id) {
        HealthDevice.GROUP_MOBILE -> "MOBILE"
        HealthDevice.GROUP_EXTERNAL -> "EXTERNAL"
        HealthDevice.GROUP_COMPANION -> "COMPANION or WATCH"
        else -> "UNKNOWN"
    }
}

To get source device information that provided sleep data when using Samsung Health Data SDK, the following example code can be used.

Getting data's source device information with Samsung Health Data SDK

suspend fun getSourceDeviceInfoOfSleepData(
    healthDataStore: HealthDataStore
) {
    val resultCount = 1
    val readRequest = DataTypes.SLEEP.readDataRequestBuilder
        .setOrdering(Ordering.DESC)
        .setLimit(resultCount)
        .build()
    try {
        val result = healthDataStore.readData(readRequest)
        result.dataList.forEach { sleepData ->
            val deviceManager = healthDataStore.getDeviceManager()
            sleepData.dataSource?.let { dataSource ->
                val device = deviceManager.getDevice(dataSource.deviceId)
                val deviceId = device?.id
                val deviceName = device?.name
                val deviceType = device?.deviceType
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Having a Trouble?

We are operating a developer support channel on the Samsung Developer site. If you encounter any issue or any question, please visit https://developer.samsung.com/dev-support and submit your query after logging in your Samsung account.