Track sleep sessions

This guide is compatible with Health Connect version 1.1.0-alpha11.

Health Connect provides a sleep session data type, to store information about a user's sleep, such as a nightly session or daytime nap. The SleepSessionRecord data type is used to represent these sessions.

Sessions allow users to measure time-based performance over a period of time, such as continuous heart rate or location data.

SleepSessionRecord sessions contain data that records sleep stages, such as AWAKE, SLEEPING and DEEP.

Subtype data is data that "belongs" to a session and is only meaningful when it's read with a parent session. For example, sleep stage.

Feature availability

There is no feature availability flag for this data type.

Required permissions

Access to sleep sessions is protected by the following permissions:

  • android.permission.health.READ_SLEEP
  • android.permission.health.WRITE_SLEEP

Declare these permissions in the Play Console for your app, as well as in your app's manifest:

<application>
  <uses-permission
android:name="android.permission.health.READ_SLEEP" />
  <uses-permission
android:name="android.permission.health.WRITE_SLEEP" />
...
</application>

You are responsible for declaring all the appropriate permissions you intend to use in your devices and apps. You should also check that each permission has been granted by the user before use

General guidance

Here are some best practice guidelines on how to work with sleep sessions in Health Connect.

  • Sessions should be used to add data from a specific sleep session, for sleep:
suspend fun writeSleepSession(healthConnectClient: HealthConnectClient) {
    healthConnectClient.insertRecords(
        listOf(
            SleepSessionRecord(
                startTime = Instant.parse("2022-05-10T23:00:00.000Z"),
                startZoneOffset = ZoneOffset.of("-08:00"),
                endTime = Instant.parse("2022-05-11T07:00:00.000Z"),
                endZoneOffset = ZoneOffset.of("-08:00"),
                title = "My Sleep"
            ),
        )
    )
}
  • Sessions should not be used for general measurements, such as daily step counts.
  • Subtype data doesn't contain a UID, but associated data has distinct UIDs.
  • Subtype data needs to be aligned in a session with sequential timestamps that don't overlap. Gaps are allowed, however.
  • Sessions are useful if the user wants data to be associated with (and tracked as part of) a session, rather than recorded continuously.

Sleep sessions

You can read or write sleep data in Health Connect. Sleep data is displayed as a session, and can be divided into 8 distinct sleep stages:

  • 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.
  • AWAKE_IN_BED: The user is awake in bed.
  • 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 a user experiences within a time range. Writing sleep stages is optional, but recommended if available.

Write sleep sessions

The SleepSessionRecord data type has two parts:

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

Here's how you insert a sleep session without stages:

SleepSessionRecord(
      title = "weekend sleep",
      startTime = startTime,
      endTime = endTime,
      startZoneOffset = ZoneOffset.UTC,
      endZoneOffset = ZoneOffset.UTC,
)

Here's how to add stages that cover the entire period of a sleep session:

val stages = listOf(
    SleepSessionRecord.Stage(
        startTime = START_TIME
        endTime = END_TIME,
        stage = SleepSessionRecord.STAGE_TYPE_SLEEPING,
    )
)

SleepSessionRecord(
        title = "weekend sleep",
        startTime = START_TIME,
        endTime = END_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endZoneOffset = END_ZONE_OFFSET,
        stages = stages,
)

Read a sleep session

For every sleep session returned, you should check whether sleep stage data is also present:

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) {
        // Retrieve relevant sleep stages from each sleep record
        val sleepStages = sleepRecord.stages
    }
}

Delete a sleep session

This is how to delete a session. For this example, we've used a sleep session:

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