HealthConnectClient


interface HealthConnectClient

Known direct subclasses
FakeHealthConnectClient

Fake HealthConnectClient to be used in tests for components that use it as a dependency.


Interface to access health and fitness records.

Summary

Constants

const Int

The Health Connect SDK APIs are available.

const Int

The Health Connect SDK is unavailable on this device at the time.

const Int

The Health Connect SDK APIs are currently unavailable, the provider is either not installed or needs to be updated.

Public companion functions

Intent
getHealthConnectManageDataIntent(
    context: Context,
    providerPackageName: String
)

Intent to open Health Connect data management screen on this phone.

HealthConnectClient
getOrCreate(context: Context, providerPackageName: String)

Retrieves an IPC-backed HealthConnectClient instance binding to an available implementation.

Int
getSdkStatus(context: Context, providerPackageName: String)

Determines whether the Health Connect SDK is available on this device at the moment.

Public companion properties

String

Intent action to open Health Connect settings on this phone.

Public functions

suspend AggregationResult

Reads AggregateMetrics according to requested read criteria: Records from AggregateRequest.dataOriginFilter and within AggregateRequest.timeRangeFilter.

suspend List<AggregationResultGroupedByDuration>

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByDurationRequest.

suspend List<AggregationResultGroupedByPeriod>

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByPeriodRequest.

open suspend MedicalDataSource
@ExperimentalPersonalHealthRecordApi
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
createMedicalDataSource(request: CreateMedicalDataSourceRequest)

Creates a MedicalDataSource using a CreateMedicalDataSourceRequest.

open suspend Unit
@ExperimentalPersonalHealthRecordApi
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
deleteMedicalDataSourceWithData(id: String)

Deletes a MedicalDataSource and all data contained within it.

open suspend Unit
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
deleteMedicalResources(ids: List<MedicalResourceId>)

Deletes a list of MedicalResources by the provided list of MedicalResourceIds.

open suspend Unit
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
deleteMedicalResources(request: DeleteMedicalResourcesRequest)

Deletes MedicalResources based on given filters in request.

suspend Unit
deleteRecords(
    recordType: KClass<Record>,
    timeRangeFilter: TimeRangeFilter
)

Deletes any Record of the given recordType in the given timeRangeFilter (automatically filtered to Record belonging to the calling application).

suspend Unit
deleteRecords(
    recordType: KClass<Record>,
    recordIdsList: List<String>,
    clientRecordIdsList: List<String>
)

Deletes one or more Record by their identifiers.

suspend ChangesResponse
getChanges(changesToken: String)

Retrieves changes in Health Connect, from a specific point in time represented by provided changesToken.

suspend String

Retrieves a changes-token, representing a point in time in the underlying Android Health Platform for a given ChangesTokenRequest.

open suspend List<MedicalDataSource>

Gets MedicalDataSources for the provided list of ids.

open suspend List<MedicalDataSource>

Gets the requested MedicalDataSources using GetMedicalDataSourcesRequest.

suspend InsertRecordsResponse

Inserts one or more Record and returns newly assigned androidx.health.connect.client.records.metadata.Metadata.id generated.

open suspend List<MedicalResource>

Reads a collection of MedicalResources given a list of MedicalResourceIds.

open suspend ReadMedicalResourcesResponse

Reads MedicalResources by request, either ReadMedicalResourcesInitialRequest or ReadMedicalResourcesPageRequest.

suspend ReadRecordResponse<T>
<T : Record> readRecord(recordType: KClass<T>, recordId: String)

Reads one Record point with its recordType and recordId.

suspend ReadRecordsResponse<T>
<T : Record> readRecords(request: ReadRecordsRequest<T>)

Retrieves a collection of Records.

suspend Unit

Updates one or more Record of given UIDs to newly specified values.

open suspend List<MedicalResource>
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
upsertMedicalResources(requests: List<UpsertMedicalResourceRequest>)

Inserts or updates a list of MedicalResources using UpsertMedicalResourceRequests.

Public properties

open HealthConnectFeatures

Access operations related to feature availability.

PermissionController

Access operations related to permissions.

Extension functions

suspend inline Unit
<T : Record> HealthConnectClient.deleteRecords(
    timeRangeFilter: TimeRangeFilter
)

Deletes any Record of type T in the given timeRangeFilter (automatically filtered to Record belonging to the calling application).

suspend inline Unit
<T : Record> HealthConnectClient.deleteRecords(
    recordIdsList: List<String>,
    clientRecordIdsList: List<String>
)

Deletes one or more Record by their identifiers.

suspend inline ReadRecordResponse<T>

Reads one Record point of type T and with the specified recordId.

Constants

SDK_AVAILABLE

Added in 1.1.0-beta02
const val SDK_AVAILABLE = 3: Int

The Health Connect SDK APIs are available.

Apps can subsequently call getOrCreate to get an instance of HealthConnectClient.

SDK_UNAVAILABLE

Added in 1.1.0-beta02
const val SDK_UNAVAILABLE = 1: Int

The Health Connect SDK is unavailable on this device at the time. This can be due to the device running a lower than required Android Version.

Apps should hide any integration points to Health Connect in this case.

SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED

Added in 1.1.0-beta02
const val SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED = 2: Int

The Health Connect SDK APIs are currently unavailable, the provider is either not installed or needs to be updated.

Apps may choose to redirect to package installers to find a suitable APK.

Public companion functions

getHealthConnectManageDataIntent

Added in 1.1.0-beta02
fun getHealthConnectManageDataIntent(
    context: Context,
    providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME
): Intent

Intent to open Health Connect data management screen on this phone. Developers should use this if they want to re-direct the user to Health Connect data management.

Parameters
context: Context

the context

providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME

optional alternative package provider to choose for backend implementation

Returns
Intent

Intent to open Health Connect data management screen.

getOrCreate

Added in 1.1.0-beta02
fun getOrCreate(
    context: Context,
    providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME
): HealthConnectClient

Retrieves an IPC-backed HealthConnectClient instance binding to an available implementation.

Parameters
context: Context

the context

providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME

optional alternative package provider to choose for backend implementation

Returns
HealthConnectClient

instance of HealthConnectClient ready for issuing requests

Throws
kotlin.UnsupportedOperationException

if service not available due to SDK version too low or running in a profile

kotlin.IllegalStateException

if the SDK is not available

See also
getSdkStatus

getSdkStatus

Added in 1.1.0-beta02
fun getSdkStatus(
    context: Context,
    providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME
): Int

Determines whether the Health Connect SDK is available on this device at the moment.

import androidx.health.connect.client.HealthConnectClient

val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName)
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
    return // early return as there is no viable integration
}
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
    // Optionally redirect to package installer to find a provider, for example:
    val uriString =
        "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding"
    context.startActivity(
        Intent(Intent.ACTION_VIEW).apply {
            setPackage("com.android.vending")
            data = Uri.parse(uriString)
            putExtra("overlay", true)
            putExtra("callerId", context.packageName)
        }
    )
    return
}
val healthConnectClient = HealthConnectClient.getOrCreate(context)
// Issue operations with healthConnectClient
Parameters
context: Context

the context

providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME

optional package provider to choose for backend implementation

Public companion properties

ACTION_HEALTH_CONNECT_SETTINGS

Added in 1.1.0-beta02
val ACTION_HEALTH_CONNECT_SETTINGSString

Intent action to open Health Connect settings on this phone. Developers should use this if they want to re-direct the user to Health Connect.

Public functions

aggregate

suspend fun aggregate(request: AggregateRequest): AggregationResult

Reads AggregateMetrics according to requested read criteria: Records from AggregateRequest.dataOriginFilter and within AggregateRequest.timeRangeFilter.

import androidx.health.connect.client.records.DistanceRecord
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter

val response =
    healthConnectClient.aggregate(
        AggregateRequest(
            metrics = setOf(DistanceRecord.DISTANCE_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
// The result may be null if no data is available in the time range.
val distanceTotalInMeters = response[DistanceRecord.DISTANCE_TOTAL]?.inMeters

Example code to retrieve statistical aggregates like maximum or minimum heart rate:

import androidx.health.connect.client.records.HeartRateRecord
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter

val response =
    healthConnectClient.aggregate(
        AggregateRequest(
            setOf(HeartRateRecord.BPM_MAX, HeartRateRecord.BPM_MIN),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
// The result may be null if no data is available in the time range.
val minimumHeartRate = response[HeartRateRecord.BPM_MIN]
val maximumHeartRate = response[HeartRateRecord.BPM_MAX]
Parameters
request: AggregateRequest

AggregateRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
AggregationResult

the AggregationResult that contains aggregated values.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example code to aggregate cumulative data like distance:

aggregateGroupByDuration

suspend fun aggregateGroupByDuration(request: AggregateGroupByDurationRequest): List<AggregationResultGroupedByDuration>

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByDurationRequest.

This method is similar to aggregate but instead of returning one AggregationResult for the entire query's time interval, it returns a list of AggregationResultGroupedByDuration, with each row keyed by start and end time. For example: steps for today bucketed by hours.

An AggregationResultGroupedByDuration is returned only if there are Record to aggregate within start and end time of the row.

import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.request.AggregateGroupByDurationRequest
import androidx.health.connect.client.time.TimeRangeFilter

val response =
    healthConnectClient.aggregateGroupByDuration(
        AggregateGroupByDurationRequest(
            metrics = setOf(StepsRecord.COUNT_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
            timeRangeSlicer = Duration.ofMinutes(1)
        )
    )
for (monthlyResult in response) {
    // The result may be null if no data is available in the time range.
    val totalSteps = monthlyResult.result[StepsRecord.COUNT_TOTAL]
}
Parameters
request: AggregateGroupByDurationRequest

AggregateGroupByDurationRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
List<AggregationResultGroupedByDuration>

a list of AggregationResultGroupedByDurations, each contains aggregated values and start/end time of the row. The list is sorted by time in ascending order.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example code to retrieve cumulative step count for each minute within provided time range:

aggregateGroupByPeriod

suspend fun aggregateGroupByPeriod(request: AggregateGroupByPeriodRequest): List<AggregationResultGroupedByPeriod>

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByPeriodRequest.

This method is similar to aggregate but instead of returning one AggregationResult for the entire query's time interval, it returns a list of AggregationResultGroupedByPeriod, with each row keyed by start and end time. For example: steps for this month bucketed by day.

An AggregationResultGroupedByPeriod is returned only if there are Record to aggregate within start and end time of the row.

import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
import androidx.health.connect.client.time.TimeRangeFilter

val response =
    healthConnectClient.aggregateGroupByPeriod(
        AggregateGroupByPeriodRequest(
            metrics = setOf(StepsRecord.COUNT_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
            timeRangeSlicer = Period.ofMonths(1)
        )
    )
for (monthlyResult in response) {
    // The result may be null if no data is available in the time range.
    val totalSteps = monthlyResult.result[StepsRecord.COUNT_TOTAL]
}
Parameters
request: AggregateGroupByPeriodRequest

AggregateGroupByPeriodRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
List<AggregationResultGroupedByPeriod>

a list of AggregationResultGroupedByPeriods, each contains aggregated values and start/end time of the row. The list is sorted by time in ascending order.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example code to retrieve cumulative step count for each month within provided time range:

createMedicalDataSource

@ExperimentalPersonalHealthRecordApi
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
open suspend fun createMedicalDataSource(request: CreateMedicalDataSourceRequest): MedicalDataSource

Creates a MedicalDataSource using a CreateMedicalDataSourceRequest.

Regarding permissions:

Medical data is represented using the Fast Healthcare Interoperability Resources (FHIR) standard.

A MedicalDataSource needs to be created before any MedicalResources for that source can be inserted. Separate MedicalDataSources should be created for medical records coming from different sources (e.g. different FHIR endpoints, different healthcare systems), unless the data has been reconciled and all records have a unique combination of resource type and resource id.

The CreateMedicalDataSourceRequest.displayName must be unique across all medical data sources created by an app, otherwise an IllegalArgumentException will be thrown. See CreateMedicalDataSourceRequest.fhirBaseUri for more details on the FHIR base URI. The data source can not be updated after creation.

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Create a `MedicalDataSource`
// Note that `displayName` must be unique across `MedicalDataSource`s
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )
Parameters
request: CreateMedicalDataSourceRequest

request containing details of the MedicalDataSource to be created

Returns
MedicalDataSource

the created MedicalDataSource

deleteMedicalDataSourceWithData

Added in 1.1.0-beta02
@ExperimentalPersonalHealthRecordApi
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
open suspend fun deleteMedicalDataSourceWithData(id: String): Unit

Deletes a MedicalDataSource and all data contained within it.

Regarding permissions:

Medical data is represented using the Fast Healthcare Interoperability Resources (FHIR) standard.

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Get or creates a `MedicalDataSource`
// Each `MedicalDataSource` is assigned an `id` by the system on creation
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

// Delete the `MedicalDataSource` that has the specified `id`
healthConnectClient.deleteMedicalDataSourceWithData(medicalDataSource.id)
Parameters
id: String

The id of the data source to delete.

Throws
kotlin.IllegalArgumentException

if id is invalid, does not exist, or owned by another app.

deleteMedicalResources

Added in 1.1.0-beta02
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
open suspend fun deleteMedicalResources(ids: List<MedicalResourceId>): Unit

Deletes a list of MedicalResources by the provided list of MedicalResourceIds.

  • If any ID in ids is invalid, the API will throw an IllegalArgumentException, and nothing will be deleted.

  • If any ID in ids does not exist, that ID will be ignored, while deletion on other IDs will be performed.

Regarding permissions:

  • Caller must hold PERMISSION_WRITE_MEDICAL_DATA in order to call this API, even then, it can only delete its own data. If any of the items in ids belongs to another app, they will be ignored.

  • Deletes are permitted in the foreground or background.

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.records.MedicalResource
import androidx.health.connect.client.records.MedicalResourceId
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest
import androidx.health.connect.client.request.UpsertMedicalResourceRequest

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Get or create a `MedicalDataSource`
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

// Insert `MedicalResource`s into the `MedicalDataSource`
val medicalResources: List<MedicalResource> =
    healthConnectClient.upsertMedicalResources(
        listOf(
            UpsertMedicalResourceRequest(
                medicalDataSource.id,
                medicalDataSource.fhirVersion,
                medicationJsonToInsert // a valid FHIR json string
            )
        )
    )

// Delete `MedicalResource`s matching the specified `dataSourceId`, `type` and `fhirResourceId`
healthConnectClient.deleteMedicalResources(
    medicalResources.map { medicalResource: MedicalResource ->
        MedicalResourceId(
            dataSourceId = medicalDataSource.id,
            fhirResourceType = medicalResource.id.fhirResourceType,
            fhirResourceId = medicalResource.id.fhirResourceId
        )
    }
)
Parameters
ids: List<MedicalResourceId>

The ids to delete.

deleteMedicalResources

Added in 1.1.0-beta02
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
open suspend fun deleteMedicalResources(request: DeleteMedicalResourcesRequest): Unit

Deletes MedicalResources based on given filters in request.

Only MedicalResources inserted by the calling app will be deleted. If the request matches any other MedicalResources, these will be ignored.

Regarding permissions:

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.records.MedicalResource
import androidx.health.connect.client.records.MedicalResource.Companion.MEDICAL_RESOURCE_TYPE_MEDICATIONS
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest
import androidx.health.connect.client.request.DeleteMedicalResourcesRequest
import androidx.health.connect.client.request.UpsertMedicalResourceRequest

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Get or create a `MedicalDataSource`
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

// Insert `MedicalResource`s into the `MedicalDataSource`
val medicalResources: List<MedicalResource> =
    healthConnectClient.upsertMedicalResources(
        listOf(
            UpsertMedicalResourceRequest(
                medicalDataSource.id,
                medicalDataSource.fhirVersion,
                medicationJsonToInsert // a valid FHIR json string
            )
        )
    )

// Delete all `MedicalResource`s that are in any pair of provided `dataSourceIds` and
// `medicalResourceTypes`
healthConnectClient.deleteMedicalResources(
    DeleteMedicalResourcesRequest(
        dataSourceIds = setOf(medicalDataSource.id),
        medicalResourceTypes = setOf(MEDICAL_RESOURCE_TYPE_MEDICATIONS)
    )
)
Parameters
request: DeleteMedicalResourcesRequest

The request that contains the filters to delete.

deleteRecords

Added in 1.1.0-beta02
suspend fun deleteRecords(
    recordType: KClass<Record>,
    timeRangeFilter: TimeRangeFilter
): Unit

Deletes any Record of the given recordType in the given timeRangeFilter (automatically filtered to Record belonging to the calling application). Deletion of multiple Record is executed in a transaction - if one fails, none is deleted.

import androidx.health.connect.client.deleteRecords
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.time.TimeRangeFilter

healthConnectClient.deleteRecords<StepsRecord>(
    timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
Parameters
recordType: KClass<Record>

Which type of Record to delete, such as StepsRecord::class

timeRangeFilter: TimeRangeFilter

The TimeRangeFilter to delete from

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example usage to delete written steps data in a time range:

deleteRecords

Added in 1.1.0-beta02
suspend fun deleteRecords(
    recordType: KClass<Record>,
    recordIdsList: List<String>,
    clientRecordIdsList: List<String>
): Unit

Deletes one or more Record by their identifiers. Deletion of multiple Record is executed in single transaction - if one fails, none is deleted.

import androidx.health.connect.client.deleteRecords
import androidx.health.connect.client.records.StepsRecord

healthConnectClient.deleteRecords<StepsRecord>(
    recordIdsList = listOf(uid1, uid2),
    clientRecordIdsList = emptyList()
)
Parameters
recordType: KClass<Record>

Which type of Record to delete, such as Steps::class

recordIdsList: List<String>

List of androidx.health.connect.client.records.metadata.Metadata.id of Record to delete

clientRecordIdsList: List<String>

List of client record IDs of Record to delete

Throws
android.os.RemoteException

For any IPC transportation failures. Deleting by invalid identifiers such as a non-existing identifier or deleting the same record multiple times will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example usage to delete written steps data by its unique identifier:

getChanges

suspend fun getChanges(changesToken: String): ChangesResponse

Retrieves changes in Health Connect, from a specific point in time represented by provided changesToken.

The response returned may not provide all the changes due to IPC or memory limits, see ChangesResponse.hasMore. Clients can make more api calls to fetch more changes from Health Connect with updated ChangesResponse.nextChangesToken.

Provided changesToken may have expired if clients have not synced for extended period of time (such as a month). In this case ChangesResponse.changesTokenExpired will be set, and clients should generate a new changes-token via getChangesToken.

val response = client.getChanges(changesToken)
if (response.changesTokenExpired) {
// Consider re-sync and fetch new changes token.
} else {
// Process new insertion/deletions, either update local storage or upload to backends.
}
Parameters
changesToken: String

A Changes-Token that represents a specific point in time in Android Health Platform.

Returns
ChangesResponse

a ChangesResponse with changes since provided changesToken.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

See also
getChangesToken

getChangesToken

suspend fun getChangesToken(request: ChangesTokenRequest): String

Retrieves a changes-token, representing a point in time in the underlying Android Health Platform for a given ChangesTokenRequest. Changes-tokens are used in getChanges to retrieve changes since that point in time.

Changes-tokens represent a point in time after which the client is interested in knowing the changes for a set of interested types of Record and optional DataOrigin filters.

Changes-tokens are only valid for 30 days after they're generated. Calls to getChanges with an expired changes-token will lead to ChangesResponse.changesTokenExpired

Parameters
request: ChangesTokenRequest

Includes interested types of record to observe changes and optional filters.

Returns
String

a changes-token

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

See also
getChanges

getMedicalDataSources

@ExperimentalPersonalHealthRecordApi
open suspend fun getMedicalDataSources(ids: List<String>): List<MedicalDataSource>

Gets MedicalDataSources for the provided list of ids.

The returned list of data sources will be in the same order as the ids.

Number of data sources returned by this API will depend based on below factors:

  • If an empty list of ids is provided, no data sources will be returned.

  • If an id is invalid or non-existent, no data source will be returned for that id, this means the returned list might have fewer elements than ids.

  • Callers will only get data sources they are permitted to get. See below.

There is no specific read permission for getting data sources. Instead, permission to read data sources is based on whether the caller has permission to read the data currently contained in that data source. Being permitted to get data sources is dependent on the following logic, in priority order, earlier statements take precedence.

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Get or create a `MedicalDataSource`
// Each `MedicalDataSource` is assigned an `id` by the system on creation
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

// Retrieve all `MedicalDataSource` with `id` matching any of the given ids
val medicalDataSources: List<MedicalDataSource> =
    healthConnectClient.getMedicalDataSources(listOf(medicalDataSource.id, anotherId))
Parameters
ids: List<String>

ids of the MedicalDataSources to retrieve

Returns
List<MedicalDataSource>

MedicalDataSources matching the provided ids

getMedicalDataSources

@ExperimentalPersonalHealthRecordApi
open suspend fun getMedicalDataSources(request: GetMedicalDataSourcesRequest): List<MedicalDataSource>

Gets the requested MedicalDataSources using GetMedicalDataSourcesRequest. Number of data sources returned by this API will depend based on below factors:

  • If an empty GetMedicalDataSourcesRequest is passed, all data sources for all apps are requested, and all which the caller is permitted to get will be returned. See below.

  • If GetMedicalDataSourcesRequest.packageNames is not empty, then only the data sources created by those packages is being requested. All data sources created by those packages which the caller is permitted to get will be returned. See below.

There is no specific read permission for getting data sources. Instead, permission to read data sources is based on whether the caller has permission to read the data currently contained in that data source. Specifically:

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest
import androidx.health.connect.client.request.GetMedicalDataSourcesRequest

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Get or create a `MedicalDataSource`
// Each `MedicalDataSource` contains the `packageName` which created it
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

// Retrieve all `MedicalDataSource`s created by any of the specified package names
// Package names may be found in other `MedicalDataSource`s or from arbitrary input
val medicalDataSources: List<MedicalDataSource> =
    healthConnectClient.getMedicalDataSources(
        GetMedicalDataSourcesRequest(listOf(medicalDataSource.packageName, anotherPackageName))
    )
Parameters
request: GetMedicalDataSourcesRequest

containing details of the MedicalDataSources to retrieve

Returns
List<MedicalDataSource>

MedicalDataSources matching the provided request

insertRecords

suspend fun insertRecords(records: List<Record>): InsertRecordsResponse

Inserts one or more Record and returns newly assigned androidx.health.connect.client.records.metadata.Metadata.id generated. Insertion of multiple records is executed in a transaction - if one fails, none is inserted.

import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.records.metadata.Metadata

val stepsRecord =
    StepsRecord(
        count = 120,
        startTime = START_TIME,
        endTime = END_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endZoneOffset = END_ZONE_OFFSET,
        metadata = Metadata.manualEntry(),
    )
healthConnectClient.insertRecords(listOf(stepsRecord))

To insert more complex data like nutrition for a user who’s eaten a banana:

import androidx.health.connect.client.records.NutritionRecord
import androidx.health.connect.client.records.metadata.Metadata
import androidx.health.connect.client.units.grams
import androidx.health.connect.client.units.kilocalories

val banana =
    NutritionRecord(
        name = "banana",
        energy = 105.0.kilocalories,
        dietaryFiber = 3.1.grams,
        potassium = 0.422.grams,
        totalCarbohydrate = 27.0.grams,
        totalFat = 0.4.grams,
        saturatedFat = 0.1.grams,
        sodium = 0.001.grams,
        sugar = 14.0.grams,
        vitaminB6 = 0.0005.grams,
        vitaminC = 0.0103.grams,
        startTime = START_TIME,
        endTime = END_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endZoneOffset = END_ZONE_OFFSET,
        metadata = Metadata.manualEntry(),
    )
healthConnectClient.insertRecords(listOf(banana))

To insert some heart rate data:

import androidx.health.connect.client.records.HeartRateRecord
import androidx.health.connect.client.records.metadata.Metadata

val heartRateRecord =
    HeartRateRecord(
        startTime = START_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endTime = END_TIME,
        endZoneOffset = END_ZONE_OFFSET,
        metadata = Metadata.manualEntry(),
        // records 10 arbitrary data, to replace with actual data
        samples =
            List(10) { index ->
                HeartRateRecord.Sample(
                    time = START_TIME + Duration.ofSeconds(index.toLong()),
                    beatsPerMinute = 100 + index.toLong(),
                )
            },
    )
healthConnectClient.insertRecords(listOf(heartRateRecord))

androidx.health.connect.client.records.metadata.Metadata.clientRecordId can be used to deduplicate data with a client provided unique identifier. When a subsequent insertRecords is called with the same androidx.health.connect.client.records.metadata.Metadata.clientRecordId, whichever Record with the higher androidx.health.connect.client.records.metadata.Metadata.clientRecordVersion takes precedence.

Parameters
records: List<Record>

List of records to insert

Returns
InsertRecordsResponse

List of unique identifiers in the order of inserted records.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

For example, to insert basic data like step counts:

readMedicalResources

@ExperimentalPersonalHealthRecordApi
open suspend fun readMedicalResources(ids: List<MedicalResourceId>): List<MedicalResource>

Reads a collection of MedicalResources given a list of MedicalResourceIds.

The number and order of medical resources returned by this API is not guaranteed, depending on a number of factors:

Each returned MedicalResource is not guaranteed to meet all requirements of the Fast Healthcare Interoperability Resources (FHIR) spec. If required, clients should perform their own validations.

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.records.MedicalResource
import androidx.health.connect.client.records.MedicalResourceId
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest
import androidx.health.connect.client.request.UpsertMedicalResourceRequest

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Get or create a `MedicalDataSource`
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

// Insert `MedicalResource`s into the `MedicalDataSource`
val medicalResources: List<MedicalResource> =
    healthConnectClient.upsertMedicalResources(
        listOf(
            UpsertMedicalResourceRequest(
                medicalDataSource.id,
                medicalDataSource.fhirVersion,
                medicationJsonToInsert // a valid FHIR json string
            )
        )
    )

// Retrieve `fhirResourceType` type `MedicalResource`s with the specified `id`s from the
// provided `MedicalDataSource`
val retrievedMedicalResources: List<MedicalResource> =
    healthConnectClient.readMedicalResources(
        medicalResources.map { medicalResource: MedicalResource ->
            MedicalResourceId(
                dataSourceId = medicalDataSource.id,
                fhirResourceType = medicalResource.id.fhirResourceType,
                fhirResourceId = medicalResource.id.fhirResourceId
            )
        }
    )
Throws
kotlin.IllegalArgumentException

if the size of ids is too large or any ID is deemed as invalid.

readMedicalResources

@ExperimentalPersonalHealthRecordApi
open suspend fun readMedicalResources(request: ReadMedicalResourcesRequest): ReadMedicalResourcesResponse

Reads MedicalResources by request, either ReadMedicalResourcesInitialRequest or ReadMedicalResourcesPageRequest.

A typical flow to read all MedicalResources that satisfy a certain criteria would be:

  1. Create a ReadMedicalResourcesInitialRequest with desired criteria, and make a request. If successful, a ReadMedicalResourcesResponse should be returned.

  2. Use returned ReadMedicalResourcesResponse.nextPageToken to create a ReadMedicalResourcesPageRequest and make another request. Again, if successful, a ReadMedicalResourcesResponse should be returned.

  3. Repeat step 2 until ReadMedicalResourcesResponse.nextPageToken is null.

Regarding permissions, only permitted MedicalResources are returned. Specifically:

Each returned MedicalResource is not guaranteed to meet all requirements of the Fast Healthcare Interoperability Resources (FHIR) spec. If required, clients should perform their own validations.

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.records.MedicalResource
import androidx.health.connect.client.records.MedicalResource.Companion.MEDICAL_RESOURCE_TYPE_LABORATORY_RESULTS
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest
import androidx.health.connect.client.request.ReadMedicalResourcesInitialRequest
import androidx.health.connect.client.request.ReadMedicalResourcesPageRequest
import androidx.health.connect.client.request.ReadMedicalResourcesRequest
import androidx.health.connect.client.response.ReadMedicalResourcesResponse

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Get or create a `MedicalDataSource`
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

// Insert `MedicalResource`s into the `MedicalDataSource`
healthConnectClient.upsertMedicalResources(exampleLabResults)

// Read `MedicalResource`s back from the `MedicalDataSource`
// Read 100 resources / page. See `pageSize` doc for defaults and limits.
val pageSize = 100
// Prepare the initial read request.
// All `MedicalResource`s in the given `MedicalDataSource`s and of given `medicalResourceType`
// will be retrieved.
val initialRequest: ReadMedicalResourcesRequest =
    ReadMedicalResourcesInitialRequest(
        MEDICAL_RESOURCE_TYPE_LABORATORY_RESULTS,
        setOf(medicalDataSource.id),
        pageSize = pageSize,
    )
// Continue reading pages until all `MedicalResource`s are read
var pageToken: String? = null
do {
    // Prepare paged request if needed
    val request: ReadMedicalResourcesRequest =
        if (pageToken == null) initialRequest
        else ReadMedicalResourcesPageRequest(pageToken, pageSize = pageSize)
    // Read `MedicalResource`s
    val response: ReadMedicalResourcesResponse =
        healthConnectClient.readMedicalResources(request)
    // Process `MedicalResource`s as desired
    val resources: List<MedicalResource> = response.medicalResources
    // Advance to next page
    pageToken = response.nextPageToken
} while (pageToken != null)

readRecord

suspend fun <T : Record> readRecord(recordType: KClass<T>, recordId: String): ReadRecordResponse<T>

Reads one Record point with its recordType and recordId.

Parameters
recordType: KClass<T>

Which type of Record to read, such as Steps::class

recordId: String

androidx.health.connect.client.records.metadata.Metadata.id of Record to read

Returns
ReadRecordResponse<T>

The Record data point.

Throws
android.os.RemoteException

For any IPC transportation failures. Update with invalid identifiers will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

readRecords

suspend fun <T : Record> readRecords(request: ReadRecordsRequest<T>): ReadRecordsResponse<T>

Retrieves a collection of Records.

import androidx.health.connect.client.readRecord
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.request.ReadRecordsRequest
import androidx.health.connect.client.time.TimeRangeFilter

val response =
    healthConnectClient.readRecords(
        ReadRecordsRequest<StepsRecord>(
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
for (stepRecord in response.records) {
    // Process each step record
}
Parameters
<T : Record>

the type of Record

request: ReadRecordsRequest<T>

ReadRecordsRequest object specifying time range and other filters

Returns
ReadRecordsResponse<T>

a response containing a collection of Records.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example code to read basic data like step counts:

updateRecords

suspend fun updateRecords(records: List<Record>): Unit

Updates one or more Record of given UIDs to newly specified values. Update of multiple records is executed in a transaction - if one fails, none is inserted.

Parameters
records: List<Record>

List of records to update

Throws
android.os.RemoteException

For any IPC transportation failures. Update with invalid identifiers will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

upsertMedicalResources

@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
open suspend fun upsertMedicalResources(requests: List<UpsertMedicalResourceRequest>): List<MedicalResource>

Inserts or updates a list of MedicalResources using UpsertMedicalResourceRequests.

In each request, from UpsertMedicalResourceRequest.dataSourceId, fhir resource type and fhir resource ID extracted from UpsertMedicalResourceRequest.data, a MedicalResourceId will be constructed. If there already exists a MedicalResource with that ID in Health Connect, then it will be updated, otherwise a new MedicalResource will be inserted.

For each UpsertMedicalResourceRequest, one MedicalResource will be returned, regardless whether it's updated or inserted. The order of the MedicalResources in the returned list will be the same as their corresponding UpsertMedicalResourceRequests in the input list.

Note that a MedicalDataSource needs to be created using createMedicalDataSource before any MedicalResources can be upserted for this source.

Regarding permissions:

Medical data is represented using the "https://hl7.org/fhir/" standard. The FHIR resource provided in UpsertMedicalResourceRequest.data is expected to be valid for the specified FHIR version according to the FHIR spec. Structural validation checks such as resource structure, field types and presence of required fields will be performed, however these checks may not cover all FHIR spec requirements and are dependant on the backing implementation of Health Connect.

Data written to Health Connect should be for a single individual only. However, the API allows for multiple Patient resources to be written to account for the possibility of multiple Patient resources being present in one individual's medical record.

Each UpsertMedicalResourceRequest also has to meet the following requirements:

If any request is failed to be processed for any reason, none of the requests will be inserted or updated in one transaction.

This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.

import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE
import androidx.health.connect.client.records.FhirVersion
import androidx.health.connect.client.records.MedicalDataSource
import androidx.health.connect.client.records.MedicalResource
import androidx.health.connect.client.request.CreateMedicalDataSourceRequest
import androidx.health.connect.client.request.UpsertMedicalResourceRequest

// Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis
if (
    healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) !=
        FEATURE_STATUS_AVAILABLE
) {
    return
}

// Get or create a `MedicalDataSource`
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

// Insert `MedicalResource`s into the `MedicalDataSource`
val medicalResources: List<MedicalResource> =
    healthConnectClient.upsertMedicalResources(
        listOf(
            UpsertMedicalResourceRequest(
                medicalDataSource.id,
                medicalDataSource.fhirVersion,
                medicationJsonToInsert // a valid FHIR json string
            )
        )
    )

// Update `MedicalResource`s in the `MedicalDataSource`
val updatedMedicalResources: List<MedicalResource> =
    healthConnectClient.upsertMedicalResources(
        listOf(
            UpsertMedicalResourceRequest(
                medicalDataSource.id,
                medicalDataSource.fhirVersion,
                // a valid FHIR json string
                // if this resource has the same type and ID as in `medicationJsonToInsert`,
                // this `upsertMedicalResources()` call will update the previously inserted
                // `MedicalResource`
                updatedMedicationJsonToInsert
            )
        )
    )
Parameters
requests: List<UpsertMedicalResourceRequest>

List of upsert requests.

Throws
kotlin.IllegalArgumentException

if any request is failed to be processed for any reason such as invalid UpsertMedicalResourceRequest.dataSourceId

java.lang.SecurityException

if caller does not hold PERMISSION_WRITE_MEDICAL_DATA.

Public properties

features

Added in 1.1.0-beta02
open val featuresHealthConnectFeatures

Access operations related to feature availability.

permissionController

Added in 1.1.0-beta02
val permissionControllerPermissionController

Access operations related to permissions.

Extension functions

suspend inline fun <T : Record> HealthConnectClient.deleteRecords(
    timeRangeFilter: TimeRangeFilter
): Unit

Deletes any Record of type T in the given timeRangeFilter (automatically filtered to Record belonging to the calling application). Deletion of multiple Record is executed in a transaction - if one fails, none is deleted.

import androidx.health.connect.client.deleteRecords
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.time.TimeRangeFilter

healthConnectClient.deleteRecords<StepsRecord>(
    timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
Parameters
<T : Record>

Which type of Record to delete, such as StepsRecord.

timeRangeFilter: TimeRangeFilter

The TimeRangeFilter to delete from

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

kotlin.IllegalStateException

If service is not available.

See also
deleteRecords

Example usage to delete written steps data in a time range:

suspend inline fun <T : Record> HealthConnectClient.deleteRecords(
    recordIdsList: List<String>,
    clientRecordIdsList: List<String>
): Unit

Deletes one or more Record by their identifiers. Deletion of multiple Record is executed in single transaction - if one fails, none is deleted.

import androidx.health.connect.client.deleteRecords
import androidx.health.connect.client.records.StepsRecord

healthConnectClient.deleteRecords<StepsRecord>(
    recordIdsList = listOf(uid1, uid2),
    clientRecordIdsList = emptyList()
)
Parameters
<T : Record>

Which type of Record to delete, such as StepsRecord.

recordIdsList: List<String>

List of androidx.health.connect.client.records.metadata.Metadata.id of Record to delete

clientRecordIdsList: List<String>

List of client record IDs of Record to delete

Throws
android.os.RemoteException

For any IPC transportation failures. Deleting by invalid identifiers such as a non-existing identifier or deleting the same record multiple times will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

kotlin.IllegalStateException

If service is not available.

See also
deleteRecords

Example usage to delete written steps data by its unique identifier:

suspend inline fun <T : Record> HealthConnectClient.readRecord(recordId: String): ReadRecordResponse<T>

Reads one Record point of type T and with the specified recordId.

Parameters
<T : Record>

Which type of Record to read, such as StepsRecord.

recordId: String

androidx.health.connect.client.records.metadata.Metadata.id of Record to read

Returns
ReadRecordResponse<T>

The Record data point.

Throws
android.os.RemoteException

For any IPC transportation failures. Update with invalid identifiers will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

kotlin.IllegalStateException

If service is not available.

See also
readRecord