Programmes d'entraînement

Ce guide est compatible avec Santé Connect version 1.1.0-alpha11.

Santé Connect fournit un type de données exercice planifié pour permettre aux applications d'entraînement d'écrire des plans d'entraînement et aux applications d'entraînement de lire des plans d'entraînement. Les exercices enregistrés (entraînements) peuvent être lus pour une analyse personnalisée des performances afin d'aider les utilisateurs à atteindre leurs objectifs d'entraînement.

Disponibilité de la fonctionnalité

Pour déterminer si l'appareil d'un utilisateur est compatible avec les plans d'entraînement sur Santé Connect, vérifiez la disponibilité de FEATURE_PLANNED_EXERCISE sur le client:

if (healthConnectClient
     .features
     .getFeatureStatus(
       HealthConnectFeatures.FEATURE_PLANNED_EXERCISE
     ) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {

  // Feature is available
} else {
  // Feature isn't available
}

Pour en savoir plus, consultez Vérifier la disponibilité des fonctionnalités.

Autorisations requises

L'accès aux plans de formation est protégé par les autorisations suivantes:

  • android.permission.health.READ_PLANNED_EXERCISE
  • android.permission.health.WRITE_PLANNED_EXERCISE

Déclarez ces autorisations dans la Play Console pour votre application, ainsi que dans le fichier manifeste de votre application:

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

Vous êtes responsable de déclarer toutes les autorisations appropriées que vous prévoyez d'utiliser dans vos appareils et applications. Vous devez également vérifier que chaque autorisation a été accordée par l'utilisateur avant utilisation.

Les plans d'entraînement sont associés aux sessions d'entraînement. Par conséquent, l'utilisateur doit autoriser l'utilisation de chaque type d'enregistrement associé à un plan d'entraînement pour exploiter pleinement cette fonctionnalité de Santé Connect.

Par exemple, si un plan d'entraînement mesure la fréquence cardiaque d'un utilisateur lors d'une série d'entraînements, les autorisations suivantes peuvent devoir être déclarées par le développeur et accordées par l'utilisateur afin d'écrire la session d'exercice et de lire les résultats pour une évaluation ultérieure:

  • android.permission.health.READ_EXERCISE
  • android.permission.health.READ_EXERCISE_ROUTE
  • android.permission.health.READ_HEART_RATE
  • android.permission.health.WRITE_EXERCISE
  • android.permission.health.WRITE_EXERCISE_ROUTE
  • android.permission.health.WRITE_HEART_RATE

Toutefois, l'application qui crée des plans d'entraînement et évalue les performances par rapport aux plans n'est souvent pas la même que celle qui consomme les plans d'entraînement et écrit les données d'exercice réelles. Selon le type d'application, toutes les autorisations de lecture et d'écriture ne sont pas nécessaires. Par exemple, vous n'avez peut-être besoin que des autorisations suivantes pour chaque type d'application:

Application de plan d'entraînement Application d'entraînement
WRITE_PLANNED_EXERCISE READ_PLANNED_EXERCISE
READ_EXERCISE WRITE_EXERCISE
READ_EXERCISE_ROUTE WRITE_EXERCISE_ROUTE
READ_HEART_RATE WRITE_HEART_RATE

Informations incluses dans un enregistrement de session d'exercice planifiée

  • Titre de la session.
  • Liste des blocs d'exercices planifiés.
  • Heures de début et de fin de la session.
  • Type d'exercice.
  • Notes sur l'activité.
  • Les métadonnées
  • ID de la session d'exercice terminée : cette valeur est écrite automatiquement une fois qu'une session d'exercice liée à cette session d'exercice planifiée est terminée.

Informations incluses dans un enregistrement de bloc d'exercice planifié

Un bloc d'exercice planifié contient une liste d'exercices, qui permet de répéter différents groupes d'exercices (par exemple, effectuer une séquence de biceps, de burpees et de crunchs cinq fois de suite).

Informations incluses dans un enregistrement d'étape d'exercice planifiée

Agrégations compatibles

Aucune agrégation n'est acceptée pour ce type de données.

Exemples d'utilisation

Supposons qu'un utilisateur planifie une course de 90 minutes dans deux jours. Cette course comprendra trois tours autour d'un lac, avec une fréquence cardiaque cible comprise entre 90 et 110 bpm.

  1. Une session d'exercice planifiée avec les éléments suivants est définie par l'utilisateur dans une application de plan d'entraînement :
    1. Début et fin prévus de l'exécution
    2. Type d'exercice (course à pied)
    3. Nombre de longueurs (répétitions)
    4. Objectif de performance pour la fréquence cardiaque (entre 90 et 110 bpm)
  2. Ces informations sont regroupées en blocs d'exercices et en étapes, et écrites dans Santé Connect par l'application de plan d'entraînement sous la forme d'un PlannedExerciseSessionRecord.
  3. L'utilisateur effectue la session planifiée (en cours d'exécution).
  4. Les données d'exercice associées à la session sont enregistrées :
    1. Par un accessoire connecté pendant la session. (par exemple, la fréquence cardiaque). Ces données sont écrites dans Santé Connect en tant que type d'enregistrement de l'activité. Dans ce cas, HeartRateRecord.
    2. Manuellement par l'utilisateur après la session. Par exemple, en indiquant le début et la fin de l'exécution réelle. Ces données sont écrites dans Santé Connect en tant que ExerciseSessionRecord.
  5. Par la suite, l'application de plan d'entraînement lit les données de Santé Connect pour évaluer les performances réelles par rapport aux objectifs fixés par l'utilisateur dans la séance d'exercice planifiée.

Planifier des exercices et définir des objectifs

Un utilisateur peut planifier son exercice à l'avance et définir des objectifs. Enregistrez-le dans Santé Connect en tant que séance d'exercice planifiée.

Dans l'exemple décrit dans la section Exemple d'utilisation, l'utilisateur planifie une course de 90 minutes dans deux jours. Cette course comprendra trois tours autour d'un lac, avec une fréquence cardiaque cible comprise entre 90 et 110 bpm.

Un extrait de code comme celui-ci peut être trouvé dans le gestionnaire de formulaire d'une application qui consigne les séances d'exercice planifiées dans Santé Connect. Il peut également se trouver au point d'intégration, par exemple avec un service de formation.

// Ensure the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(PlannedExerciseSessionRecord::class))) {
    // The user hasn't granted the app permission to write planned exercise session data.
    return
}

val plannedDuration = Duration.ofMinutes(90)
val plannedStartDate = LocalDate.now().plusDays(2)

val plannedExerciseSessionRecord = PlannedExerciseSessionRecord(
    startDate = plannedStartDate,
    duration = plannedDuration,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    blocks = listOf(
        PlannedExerciseBlock(
            repetitions = 1, steps = listOf(
                PlannedExerciseStep(
                    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
                    exercisePhase = PlannedExerciseStep.EXERCISE_PHASE_ACTIVE,
                    completionGoal = ExerciseCompletionGoal.RepetitionsGoal(repetitions = 3),
                    performanceTargets = listOf(
                        ExercisePerformanceTarget.HeartRateTarget(
                            minHeartRate = 90.0, maxHeartRate = 110.0
                        )
                    )
                ),
            ), description = "Three laps around the lake"
        )
    ),
    title = "Run at lake",
    notes = null
)
val insertedPlannedExerciseSessions =
    healthConnectClient.insertRecords(listOf(plannedExerciseSessionRecord)).recordIdsList
val insertedPlannedExerciseSessionId = insertedPlannedExerciseSessions.first()

Enregistrer des données sur l'exercice et l'activité

Deux jours plus tard, l'utilisateur enregistre la session d'entraînement réelle. Écrivez-le dans Santé Connect en tant que séance d'exercice.

Dans cet exemple, la durée de la session de l'utilisateur correspond exactement à la durée planifiée.

L'extrait de code suivant peut se trouver dans le gestionnaire de formulaire d'une application qui consigne les séances d'exercice dans Santé Connect. Il peut également être présent dans les gestionnaires d'ingestion et d'exportation de données d'un accessoire connecté capable de détecter et de consigner des séances d'exercice.

insertedPlannedExerciseSessionId est réutilisé dans l'exemple précédent. Dans une application réelle, l'ID serait déterminé par l'utilisateur qui sélectionne une séance d'exercice planifiée dans une liste de sessions existantes.

// Ensure the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(ExerciseSessionRecord::class))) {
    // The user doesn't granted the app permission to write exercise session data.
    return
}

val sessionDuration = Duration.ofMinutes(90)
val sessionEndTime = Instant.now()
val sessionStartTime = sessionEndTime.minus(sessionDuration)

val exerciseSessionRecord = ExerciseSessionRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    segments = listOf(
        ExerciseSegment(
            startTime = sessionStartTime,
            endTime = sessionEndTime,
            repetitions = 3,
            segmentType = ExerciseSegment.EXERCISE_SEGMENT_TYPE_RUNNING
        )
    ),
    title = "Run at lake",
    plannedExerciseSessionId = insertedPlannedExerciseSessionId,
)
val insertedExerciseSessions =
    healthConnectClient.insertRecords(listOf(exerciseSessionRecord))

Un wearable enregistre également sa fréquence cardiaque tout au long de la course. L'extrait de code suivant peut être utilisé pour générer des enregistrements dans la plage cible.

Dans une application réelle, les éléments principaux de cet extrait se trouvent peut-être dans le gestionnaire d'un message provenant d'un accessoire connecté, qui écrirait la mesure dans Santé Connect lors de la collecte.

// Ensure the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(HeartRateRecord::class))) {
    // The user doesn't granted the app permission to write heart rate record data.
    return
}

val samples = mutableListOf<HeartRateRecord.Sample>()
var currentTime = sessionStartTime
while (currentTime.isBefore(sessionEndTime)) {
    val bpm = Random.nextInt(21) + 90
    val heartRateRecord = HeartRateRecord.Sample(
        time = currentTime,
        beatsPerMinute = bpm.toLong(),
    )
    samples.add(heartRateRecord)
    currentTime = currentTime.plusSeconds(180)
}

val heartRateRecord = HeartRateRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    samples = samples,
)
val insertedHeartRateRecords = healthConnectClient.insertRecords(listOf(heartRateRecord))

Évaluer les objectifs de performances

Le jour suivant l'entraînement de l'utilisateur, vous pouvez récupérer l'exercice enregistré, rechercher les objectifs d'exercice planifiés et évaluer d'autres types de données pour déterminer si les objectifs définis ont été atteints.

Un extrait de code comme celui-ci se trouve probablement dans une tâche périodique pour évaluer les objectifs de performances ou lors du chargement d'une liste d'exercices et de l'affichage d'une notification sur les objectifs de performances dans une application.

// Ensure the user has granted all necessary permissions for this task
val grantedPermissions =
     healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.containsAll(
        listOf(
            HealthPermission.getReadPermission(ExerciseSessionRecord::class),
            HealthPermission.getReadPermission(PlannedExerciseSessionRecord::class),
            HealthPermission.getReadPermission(HeartRateRecord::class)
        )
    )
) {
    // The user doesn't granted the app permission to read exercise session record data.
    return
}

val searchDuration = Duration.ofDays(1)
val searchEndTime = Instant.now()
val searchStartTime = searchEndTime.minus(searchDuration)

val response = healthConnectClient.readRecords(
    ReadRecordsRequest<ExerciseSessionRecord>(
        timeRangeFilter = TimeRangeFilter.between(searchStartTime, searchEndTime)
    )
)
for (exerciseRecord in response.records) {
    val plannedExerciseRecordId = exerciseRecord.plannedExerciseSessionId
    val plannedExerciseRecord =
        if (plannedExerciseRecordId == null) null else healthConnectClient.readRecord(
            PlannedExerciseSessionRecord::class, plannedExerciseRecordId
        ).record
    if (plannedExerciseRecord != null) {
        val aggregateRequest = AggregateRequest(
            metrics = setOf(HeartRateRecord.BPM_AVG),
            timeRangeFilter = TimeRangeFilter.between(
                exerciseRecord.startTime, exerciseRecord.endTime
            ),
        )
        val aggregationResult = healthConnectClient.aggregate(aggregateRequest)

        val maxBpm = aggregationResult[HeartRateRecord.BPM_MAX]
        val minBpm = aggregationResult[HeartRateRecord.BPM_MIN]
        if (maxBpm != null && minBpm != null) {
            plannedExerciseRecord.blocks.forEach { block ->
                block.steps.forEach { step ->
                    step.performanceTargets.forEach { target ->
                        when (target) {
                            is ExercisePerformanceTarget.HeartRateTarget -> {
                                val minTarget = target.minHeartRate
                                val maxTarget = target.maxHeartRate
                                if(
                                    minBpm >= minTarget && maxBpm <= maxTarget
                                ) {
                                  // Success!
                                }
                            }
                            // Handle more target types
                            }
                        }
                    }
                }
            }
        }
    }
}