Work with sessions

Sleep and Activity data types in Health Connect rely on sessions. A session is a time interval during which a user performs an activity. Activity sessions in Health Connect can include anything from running to badminton. Sessions allow users to measure time-based performance. This data records an array of instantaneous samples measured over a period of time, for example a continuous heart rate or location samples during an activity.

The following provides additional information and best practices on how to work with sessions in Health Connect:

  • When to create a session: If you're adding data from a specific workout or activity, or for sleep.
  • When not to create a session: For general measurements like daily step counts.

  • Sessions have a single UID but data within sessions have their own UIDs.

  • Sessions are metadata. They’re specifically useful for instances where the user wants data to be associated with and tracked as part of a session, rather than recorded for a continuous all-day tracker, like a daily step count, for example.

  • Nothing prevents a single application from writing multiple sessions or overlapping them in the same timeframe. Multiple applications can also write multiple sessions into the same timeframe.

Sleep sessions

You can read or write sleep data in Health Connect. It is displayed as a session and can be divided into sleep stages.

Sleep stages include:

  • UNKNOWN : Unspecified or unknown if the user is sleeping.
  • AWAKE : The user is awake (within a sleep cycle, not during the day).
  • SLEEPING : Generic or non-granular sleep description.
  • OUT_OF_BED : The user gets out of bed in the middle of a sleep session.
  • LIGHT : The user is in a light sleep cycle.
  • DEEP : The user is in a deep sleep cycle.
  • REM : The user is in a REM sleep cycle.

These values represent the type of sleep the user was in throughout a time range. Writing sleep stages is optional, but recommended if available.

Writing sleep sessions with or without sleep stages

The Sleep data type in Health Connect has two key parts to it:

  1. The overall session, spanning the entire duration of sleep.
  2. Individual stages during the sleep session such as light sleep or deep sleep.

The following demonstrates how to insert a sleep session, first without stages:

suspend fun writeSleepSession(healthConnectClient: HealthConnectClient) {
    val sleepSession = SleepSessionRecord(
        // Optionally add a title
        title = "My sleep",
        // Optionally add some notes
        notes = "Managed to get a good night of sleep",
        startTime = START_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endTime = END_TIME,
        endZoneOffset = END_TIME_OFFSET
    )
    healthConnectClient.insertRecords(
        listOf(sleepSession)
    )
}

If adding sleep stages, add stages wherever possible to cover the entire period of the overarching sleep session:

suspend fun writeSleepStages(healthConnectClient: HealthConnectClient) {
    // List of sleep stages covering the whole night. In this example, only the
    // first and last is shown, showing alignment to the start and end time of the
    // overarching session.
    val sleepStages = listOf(
        // First sleep stage of the night.
        SleepStageRecord(
            stage = SleepStageRecord.StageType.LIGHT,
            startTime = START_TIME,
            startZoneOffset = START_ZONE_OFFSET,
            endTime = ...,
            endZoneOffset = ...
        ),
        // ... <N further sleep stages for the night>
        // Finally, the last sleep stage of the night:
        SleepStageRecord(
            stage = SleepStageRecord.StageType.SLEEPING,
            startTime = ... ,
            startZoneOffset = ...,
            endTime = END_TIME,
            endZoneOffset = END_ZONE_OFFSET
        )
    )
    healthConnectClient.insertRecords(sleepStages)
}

Reading sleep sessions

The following demonstrates reading sleep sessions between two points in time. For every sleep session returned, you should check whether sleep stage data is also available, as shown:

suspend fun readSleepSessions(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response =
        healthConnectClient.readRecords(
            ReadRecordsRequest(
                SleepSessionRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
    for (sleepRecord in response.records) {
        // Process each exercise record
        // Optionally pull in sleep stages of the same time range
        val sleepStageRecords =
            healthConnectClient
                .readRecords(
                    ReadRecordsRequest(
                        SleepStageRecord::class,
                        timeRangeFilter =
                            TimeRangeFilter.between(sleepRecord.startTime, sleepRecord.endTime)
                    )
                )
                .records
    }
}

Deleting a session

The following code sample demonstrates how to delete a sleep session.

suspend fun deleteSleepSession(
    healthConnectClient: HealthConnectClient,
    sleepRecord: SleepSessionRecord,
) {
    val timeRangeFilter = TimeRangeFilter.between(sleepRecord.startTime, sleepRecord.endTime)
    healthConnectClient.deleteRecords(SleepSessionRecord::class, timeRangeFilter)
    healthConnectClient.deleteRecords(SleepStageRecord::class, timeRangeFilter)
}

Exercise sessions

Exercise sessions can include anything from running to badminton in Health Connect. The following examples show you how to write and read an exercise session.

Writing exercise sessions

The following code sample demonstrates how to build an insertion request that includes a session:

suspend fun writeExerciseSession(healthConnectClient: HealthConnectClient) {
    healthConnectClient.insertRecords(
        listOf(
            ExerciseSessionRecord(
                startTime = START_TIME,
                startZoneOffset = START_ZONE_OFFSET,
                endTime = END_TIME,
                endZoneOffset = END_ZONE_OFFSET,
                exerciseType = ExerciseSessionRecord.ExerciseType.RUNNING,
                title = "My Run"
            ),
            DistanceRecord(
                startTime = START_TIME,
                startZoneOffset = START_ZONE_OFFSET,
                endTime = END_TIME,
                endZoneOffset = END_ZONE_OFFSET,
                distance = 5000.meters
            ),
            // ... other records
        )
    )
}

Note how in the previous example, a record is added for Distance, which spans the entire duration of the session, but data can be added with different granularity.

If the app had measured distance regularly during the run, then another approach would be to include many Distance records, each representing the distance covered in a portion of the run.

Reading exercise sessions

Here’s an example of how to read exercise sessions:

suspend fun readExerciseSessions(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response =
        healthConnectClient.readRecords(
            ReadRecordsRequest(
                ExerciseSessionRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
    for (exerciseRecord in response.records) {
        // Process each exercise record
        // Optionally pull in with other data sources of the same time range.
        val heartRateRecords =
            healthConnectClient
                .readRecords(
                    ReadRecordsRequest(
                        HeartRateRecord::class,
                        timeRangeFilter =
                            TimeRangeFilter.between(
                                exerciseRecord.startTime,
                                exerciseRecord.endTime
                            )
                    )
                )
                .records
    }
}