Monitorar passos

A Conexão Saúde oferece um tipo de dados passos para registrar contagens de passos usando o StepsRecord. Os passos são uma medida fundamental no monitoramento de saúde e condicionamento físico.

Ler passos no dispositivo móvel

Com o Android 14 (nível 34 da API) e a extensão do SDK versão 20 ou mais recente, a Conexão Saúde oferece a contagem de passos no dispositivo. Se algum app tiver recebido a permissão READ_STEPS, a Conexão Saúde vai começar a capturar passos do dispositivo Android, e os usuários vão ver os dados de passos adicionados automaticamente às entradas de Passos da Conexão Saúde.

Para verificar se a contagem de passos no dispositivo está disponível, confira se o dispositivo está executando o Android 14 (nível 34 da API) e tem pelo menos a extensão do SDK versão 20:

val isStepTrackingAvailable =
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
        SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 20

Se o app ler contagens de passos agregadas usando aggregate e não filtrar por DataOrigin, os passos no dispositivo serão incluídos automaticamente no total, e nenhuma mudança será necessária para a atualização de junho de 2026.

Mudança de atribuição para passos no dispositivo

A partir da atualização de junho de 2026, os passos rastreados nativamente pela Conexão Saúde serão atribuídos a um nome de pacote sintético (SPN), como com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e.

Anteriormente, os passos integrados eram atribuídos ao nome do pacote android. Os dados históricos de passos registrados antes de junho de 2026 mantêm o nome do pacote android.

Os SPNs são específicos do dispositivo e têm escopo por aplicativo para proteger a privacidade do usuário:

  • Estável:o SPN do dispositivo atual é estável para seu aplicativo.
  • Com escopo do aplicativo:aplicativos diferentes no mesmo dispositivo mostram SPNs diferentes para dados de passos no dispositivo.

Consultar passos no dispositivo

Como os SPNs têm escopo e são específicos do dispositivo, não codifique valores de SPN. Em vez disso, use a API getCurrentDeviceDataSource() para recuperar o SPN do dispositivo atual.

Embora a contagem de passos no dispositivo exija a extensão do SDK versão 20 ou mais recente, a API getCurrentDeviceDataSource() está disponível no Android 14 (nível 34 da API) com a extensão do SDK versão 11 ou mais recente.

A API getCurrentDeviceDataSource() ainda não está disponível na biblioteca Jetpack da Conexão Saúde. Os exemplos a seguir usam a API de framework do Android:

import android.content.Context
import android.health.connect.HealthConnectManager

val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)
val deviceDataSource = healthConnectManager?.getCurrentDeviceDataSource()
val currentDeviceSpn = deviceDataSource?.deviceDataOrigin?.packageName

Se o app precisar ler passos no dispositivo ou mostrar dados de passos detalhados por aplicativo ou dispositivo de origem, consulte os registros em que o DataOrigin é android ou corresponde ao SPN do dispositivo. Se o app mostrar a atribuição de dados de passos, use metadata.device para identificar o dispositivo de origem de registros individuais. Para passos no dispositivo identificados por um SPN em dados agregados, você pode usar metadados do dispositivo, como model ou manufacturer de DeviceDataSource para atribuição, ou usar um rótulo genérico, como "Seu smartphone" para passos no dispositivo.

O exemplo a seguir mostra como ler dados agregados de contagem de passos no dispositivo filtrando por android e pelo SPN do dispositivo atual:

import android.content.Context
import android.health.connect.HealthConnectManager
import android.os.Build
import android.os.ext.SdkExtensions
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.records.metadata.DataOrigin
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter
import java.time.Instant

suspend fun readDeviceStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    context: Context,
    startTime: Instant,
    endTime: Instant
) {
    // 1. Check if SDK Extension 11+ is available for getCurrentDeviceDataSource()
    val isDataSourceApiAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.U &&
            SdkExtensions.getExtensionVersion(Build.VERSION_CODES.U) >= 11

    try {
        val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)

        // 2. Safely fetch the package name only if API is available and data exists
        val currentDeviceSpn = if (isDataSourceApiAvailable) {
            healthConnectManager?.getCurrentDeviceDataSource()?.deviceDataOrigin?.packageName
        } else {
            null
        }

        val dataOriginFilters = mutableSetOf(DataOrigin("android"))

        // 3. Explicit null-safety check using .let
        currentDeviceSpn?.let {
            dataOriginFilters.add(DataOrigin(it))
        }

        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                dataOriginFilter = dataOriginFilters
            )
        )

        val stepCount = response[StepsRecord.COUNT_TOTAL]

    } catch (e: Exception) {
        // Now this catch block only handles actual runtime exceptions, 
        // rather than Errors from missing methods.
    }
}

Contagem de passos no dispositivo

  • Uso do sensor: a Conexão Saúde usa o sensor TYPE_STEP_COUNTER de SensorManager. Esse sensor é otimizado para baixo consumo de energia, o que o torna ideal para o rastreamento contínuo de passos em segundo plano.
  • Granularidade dos dados: para conservar a duração da bateria, os dados de passos são normalmente agrupados e gravados no banco de dados da Conexão Saúde com uma frequência máxima de uma vez por minuto.
  • Atribuição: os passos registrados por esse recurso antes de junho de 2026 são atribuídos ao nome do pacote android no DataOrigin. Após essa data, eles são atribuídos a um SPN específico do dispositivo. Consulte Mudança de atribuição para passos no dispositivo.
  • Ativação: o mecanismo de contagem de passos no dispositivo só fica ativo quando pelo menos um aplicativo no dispositivo recebe a READ_STEPS permissão na Conexão Saúde.

Verificar a disponibilidade da Conexão Saúde

Antes de tentar usar a Conexão Saúde, o app precisa verificar se ela está disponível no dispositivo do usuário. A Conexão Saúde pode não estar pré-instalada em todos os dispositivos ou pode estar desativada. É possível verificar a disponibilidade usando o método HealthConnectClient.getSdkStatus().

Como verificar a disponibilidade da Conexão Saúde

fun checkHealthConnectAvailability(context: Context) {
    val providerPackageName = "com.google.android.apps.healthdata" // Or get from HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME
    val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName)

    if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
      // Health Connect is not available. Guide the user to install/enable it.
      // For example, show a dialog.
      return // early return as there is no viable integration
    }
    if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
      // Health Connect is available but requires an update.
      // 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
    }
    // Health Connect is available, obtain a HealthConnectClient instance
    val healthConnectClient = HealthConnectClient.getOrCreate(context)
    // Issue operations with healthConnectClient
}

Dependendo do status retornado por getSdkStatus(), você pode orientar o usuário a instalar ou atualizar a Conexão Saúde na Google Play Store, se necessário.

Permissões necessárias

O acesso aos passos é protegido pelas seguintes permissões:

  • android.permission.health.READ_STEPS
  • android.permission.health.WRITE_STEPS

Para adicionar a capability de passos ao app, comece solicitando permissões para o tipo de dados Steps.

Confira a permissão necessária para poder gravar passos:

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

Para ler passos, é necessário solicitar as seguintes permissões:

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

Solicitar permissões do usuário

Depois de criar uma instância de cliente, seu app precisa solicitar permissões aos usuários. Eles precisam concedê-las ou negá-las a qualquer momento. Para fazer isso, crie um conjunto de permissões para os tipos de dados necessários. Verifique se as permissões no conjunto foram declaradas primeiro no manifesto do Android.

val permissions =
    setOf(
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class)
    )
Use getGrantedPermissions para verificar se o app já tem as permissões necessárias concedidas. Caso contrário, use createRequestPermissionResultContract para solicitar essas permissões. Isso mostra a tela de permissões da Conexão Saúde.
val permissions = setOf(
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class),
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class)
    )

val requestPermissionsLauncher = rememberLauncherForActivityResult(
    contract = PermissionController.createRequestPermissionResultContract()
) { grantedPermissions ->
    if (grantedPermissions.containsAll(permissions)) {
        coroutineScope.launch { snackbarHostState.showSnackbar("Permissions granted!") }
    } else {
        coroutineScope.launch { snackbarHostState.showSnackbar("Permissions denied.") }
    }
}
Como os usuários podem conceder ou revogar permissões a qualquer momento, seu app precisa verificar as permissões sempre antes de usá-las e lidar com cenários em que a permissão é perdida.

Informações incluídas em um registro de passos

Cada StepsRecord contém as seguintes informações:

  • count: o número de passos dados no intervalo de tempo, como um Long.
  • startTime: a hora de início do intervalo de medição.
  • endTime: a hora de término do intervalo de medição.
  • startZoneOffset: o deslocamento de zona para a hora de início.
  • endZoneOffset: o deslocamento de zona para a hora de término.

Agregações aceitas

Os seguintes valores agregados estão disponíveis para StepsRecord:

Os seguintes valores agregados estão disponíveis para StepsCadenceRecord:

Exemplo de uso

As seções a seguir mostram como ler e gravar dados StepsRecord.

Gravar dados de passos

O app pode gravar dados de contagem de passos inserindo StepsRecord instâncias. O exemplo a seguir mostra como registrar 1.000 passos dados por um usuário:

val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime)
val stepsRecord = StepsRecord(
    count = 120,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = zoneOffset,
    endZoneOffset = zoneOffset,
    metadata = Metadata(
        device = Device(type = Device.TYPE_WATCH),
        recordingMethod = Metadata.RECORDING_METHOD_AUTOMATICALLY_RECORDED
    )
)
healthConnectClient.insertRecords(listOf(stepsRecord))

Ler dados agregados

A maneira mais comum de ler dados de passos é agregar o total de passos em um período. O exemplo a seguir mostra como ler a contagem total de passos de um usuário em um determinado período:

suspend fun readStepsAggregate(startTime: Instant, endTime: Instant): Long {
    val response = healthConnectClient.aggregate(
        AggregateRequest(
            metrics = setOf(StepsRecord.COUNT_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
    return response[StepsRecord.COUNT_TOTAL] ?: 0L
}

Ler dados brutos

O exemplo a seguir mostra como ler dados brutos de StepsRecord dados entre um horário de início e término:

val response = healthConnectClient.readRecords(
    ReadRecordsRequest(
        StepsRecord::class,
        timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
    )
)
response.records.forEach { record ->
    /* Process records */
}