Ce guide est compatible avec Santé Connect version 1.1.0-alpha12.
Les parcours sportifs permettent aux utilisateurs de suivre un itinéraire GPS pour les activités physiques associées et de partager des cartes de leurs entraînements avec d'autres applications.
Vérifier la disponibilité de Santé Connect
Avant de tenter d'utiliser Santé Connect, votre application doit vérifier que Santé Connect est disponible sur l'appareil de l'utilisateur. Il est possible que Santé Connect ne soit pas préinstallé sur tous les appareils ou qu'il soit désactivé.
Vous pouvez vérifier la disponibilité à l'aide de la méthode HealthConnectClient.getSdkStatus().
Vérifier la disponibilité de Santé Connect
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 }
En fonction de l'état renvoyé par getSdkStatus(), vous pouvez inviter l'utilisateur à installer ou à mettre à jour Santé Connect depuis le Google Play Store si nécessaire.
Ce guide explique comment demander des autorisations à l'utilisateur et comment les applications sont autorisées à écrire des données de parcours dans le cadre d'une session sportive.
Les fonctionnalités de lecture et d'écriture des parcours sportifs incluent les éléments suivants :
- Les applications créent une autorisation d'écriture pour les parcours sportifs.
- L'insertion se produit en écrivant une session sportive dont le champ est un parcours.
- Lecture :
- Pour le propriétaire de la session, les données sont accessibles par le biais d'une lecture de session.
- À partir d'une application tierce, une boîte de dialogue permet à l'utilisateur d'accorder une lecture unique d'un parcours.
Si l'utilisateur ne dispose pas d'autorisations d'écriture et que le parcours n'est pas défini, celui-ci n'est pas mis à jour.
Si votre application dispose d'une autorisation d'écriture sur le parcours et tente de mettre à jour une session en transmettant un objet de session sans le parcours, le parcours existant est supprimé.
Disponibilité de la fonctionnalité
Pour déterminer si l'appareil d'un utilisateur est compatible avec l'exercice planifié sur Santé Connect, vérifiez la disponibilité deFEATURE_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
}
Autorisations requises
L'accès au parcours sportif est protégé par les autorisations suivantes :
android.permission.health.READ_EXERCISE_ROUTESandroid.permission.health.WRITE_EXERCISE_ROUTE
READ_EXERCISE_ROUTES est au pluriel, tandis que WRITE_EXERCISE_ROUTE est au singulier.
Pour ajouter la fonctionnalité de parcours sportifs à votre application, commencez par demander des autorisations pour le type de données ExerciseSession.
Voici l'autorisation que vous devez déclarer pour pouvoir écrire un parcours sportif :
<application>
<uses-permission
android:name="android.permission.health.WRITE_EXERCISE_ROUTE" />
...
</application>
Pour lire un parcours sportif, vous devez demander les autorisations suivantes :
<application>
<uses-permission
android:name="android.permission.health.READ_EXERCISE_ROUTES" />
...
</application>
Vous devez également déclarer une autorisation, car chaque parcours est associé à une session sportive (une session = un entraînement).
Pour demander des autorisations, utilisez la méthode PermissionController.createRequestPermissionResultContract() lorsque vous connectez votre application pour la première fois à Santé Connect. Vous pouvez demander plusieurs autorisations :
- Lire les données de santé et de fitness, y compris les données de parcours :
HealthPermission.getReadPermission(ExerciseSessionRecord::class) - Écrire des données de santé et de fitness, y compris des données de parcours :
HealthPermission.getWritePermission(ExerciseSessionRecord::class) - Écrire des données de parcours sportif :
HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE
Demander des autorisations à l'utilisateur
Après avoir créé une instance de client, votre application doit demander des autorisations à l'utilisateur. Les utilisateurs doivent être autorisés à accorder ou à refuser des autorisations à tout moment.
Pour ce faire, créez un ensemble d'autorisations pour les types de données requis. Assurez-vous d'abord que les autorisations de l'ensemble sont déclarées dans votre fichier manifeste Android.
// Create a set of permissions for required data types
val PERMISSIONS =
setOf(
HealthPermission.getReadPermission(ExerciseSessionRecord::class),
HealthPermission.getWritePermission(ExerciseSessionRecord::class)
)
Utilisez getGrantedPermissions pour voir si votre application dispose déjà des
autorisations requises accordées. Si ce n'est pas le cas, utilisez
createRequestPermissionResultContract pour demander
ces autorisations. L'écran des autorisations de Santé Connect s'affiche.
// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()
val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
if (granted.containsAll(PERMISSIONS)) {
// Permissions successfully granted
} else {
// Lack of required permissions
}
}
suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
val granted = healthConnectClient.permissionController.getGrantedPermissions()
if (granted.containsAll(PERMISSIONS)) {
// Permissions already granted; proceed with inserting or reading data
} else {
requestPermissions.launch(PERMISSIONS)
}
}
Étant donné que les utilisateurs peuvent accorder ou révoquer des autorisations à tout moment, votre application doit vérifier les autorisations chaque fois avant de les utiliser et gérer les scénarios dans lesquels l'autorisation est perdue.
Informations incluses dans un enregistrement de session sportive
Chaque enregistrement de session sportive contient les informations suivantes :
- Le type d'exercice, par exemple le vélo.
- Le parcours sportif, qui contient des informations telles que la latitude, la longitude et l'altitude.
Agrégations compatibles
Les valeurs agrégées suivantes sont disponibles pour
ExerciseSessionRecord :
Exemple d'utilisation
Les extraits de code suivants montrent comment lire et écrire un itinéraire d'exercice.
Lire le parcours sportif
Votre application ne peut pas lire les données de parcours sportif créées par d'autres applications lorsqu'elle s'exécute en arrière-plan.
Lorsque votre application s'exécute en arrière-plan et tente de lire un parcours sportif créé par une autre application, Santé Connect renvoie une réponse ExerciseRouteResult.ConsentRequired, même si votre application dispose de l'autorisation Toujours autoriser pour accéder aux données de parcours sportif.
Pour cette raison, nous vous recommandons vivement de demander des parcours lors d'une interaction délibérée de l'utilisateur avec votre application, lorsque l'utilisateur est activement engagé avec l'interface utilisateur de votre application.
Pour en savoir plus sur les lectures en arrière-plan, consultez l'exemple de lecture en arrière-plan.
L'extrait de code suivant montre comment lire une session dans Santé Connect et demander un itinéraire à partir de cette session :
private suspend fun readExerciseSessionAndRoute() { val client = healthConnectClient ?: return val endTime = Instant.now() val startTime = endTime.minus(Duration.ofHours(1)) val grantedPermissions = client.permissionController.getGrantedPermissions() // 1. Verify basic Exercise Session permissions if (!grantedPermissions.contains( HealthPermission.getReadPermission(ExerciseSessionRecord::class) ) ) { return } // 2. Read the sessions val readResponse = client.readRecords( ReadRecordsRequest( ExerciseSessionRecord::class, TimeRangeFilter.between(startTime, endTime) ) ) val exerciseRecord = readResponse.records.firstOrNull() ?: return val recordId = exerciseRecord.metadata.id // 3. Read the specific record to check for the route val sessionResponse = client.readRecord(ExerciseSessionRecord::class, recordId) // 4. Handle the Route Result directly from the response when (val routeResult = sessionResponse.record.exerciseRouteResult) { is ExerciseRouteResult.Data -> { displayExerciseRoute(routeResult.exerciseRoute) } is ExerciseRouteResult.ConsentRequired -> { // Since you are in a Service, you cannot launch ActivityResultLauncher. // Send a notification to the user to grant route-specific consent. handleConsentRequired(recordId) } is ExerciseRouteResult.NoData -> Unit else -> Unit } } private fun displayExerciseRoute(route: ExerciseRoute) { val locations = route.route.orEmpty() for (location in locations) { println(location) } }
Écrire un parcours sportif
Le code suivant montre comment enregistrer une session comprenant un parcours sportif :
private suspend fun insertExerciseRoute() { val client = healthConnectClient ?: return val grantedPermissions = client.permissionController.getGrantedPermissions() // 1. Verify Session Write Permission val hasWriteSession = grantedPermissions.contains( HealthPermission.getWritePermission(ExerciseSessionRecord::class) ) if (!hasWriteSession) return val sessionStartTime = Instant.now() val sessionDuration = Duration.ofMinutes(20) val sessionEndTime = sessionStartTime.plus(sessionDuration) // 2. Build the route if route-specific write permission is granted val hasWriteRoute = grantedPermissions.contains(HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE) val exerciseRoute = if (hasWriteRoute) { ExerciseRoute( listOf( ExerciseRoute.Location( time = sessionStartTime, latitude = 6.5483, longitude = 0.5488, horizontalAccuracy = Length.meters(2.0), verticalAccuracy = Length.meters(2.0), altitude = Length.meters(9.0), ), ExerciseRoute.Location( time = sessionEndTime.minusSeconds(1), latitude = 6.4578, longitude = 0.6577, horizontalAccuracy = Length.meters(2.0), verticalAccuracy = Length.meters(2.0), altitude = Length.meters(9.2), ) ) ) } else { null } // 3. Create the session record val exerciseSessionRecord = ExerciseSessionRecord( startTime = sessionStartTime, startZoneOffset = ZoneOffset.UTC, endTime = sessionEndTime, endZoneOffset = ZoneOffset.UTC, exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_BIKING, title = "Morning Bike Ride", exerciseRoute = exerciseRoute, metadata = Metadata( device = Device(type = Device.TYPE_PHONE) ) ) // 4. Insert into Health Connect client.insertRecords(listOf(exerciseSessionRecord)) }
Sessions d'exercice
Les sessions d'exercice peuvent inclure toutes sortes d'activités, de la course à pied au badminton.
Écrire des sessions d'exercice
Voici comment créer une requête d'insertion incluant une 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",
metadata = Metadata.manualEntry()
),
// ... other records
)
)
}
Lire une session d'exercice
Voici un exemple de lecture d'une session d'exercice :
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 distanceRecord =
healthConnectClient
.readRecords(
ReadRecordsRequest(
DistanceRecord::class,
timeRangeFilter =
TimeRangeFilter.between(
exerciseRecord.startTime,
exerciseRecord.endTime
)
)
)
.records
}
}
Écrire des données de sous-type
Les sessions peuvent également être constituées de données de sous-type facultatives, qui enrichiront la session avec des informations supplémentaires.
Par exemple, les sessions d'exercice peuvent inclure les classes ExerciseSegment, ExerciseLap et ExerciseRoute :
val segments = listOf(
ExerciseSegment(
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
segmentType = ActivitySegmentType.BENCH_PRESS,
repetitions = 373
)
)
val laps = listOf(
ExerciseLap(
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
length = 0.meters
)
)
ExerciseSessionRecord(
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_CALISTHENICS,
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
startZoneOffset = ZoneOffset.UTC,
endZoneOffset = ZoneOffset.UTC,
segments = segments,
laps = laps,
route = route,
metadata = Metadata.manualEntry()
)
Supprimer une session d'exercice
Il existe deux façons de supprimer une session d'exercice :
- Par période de temps
- Par UID
Voici comment supprimer les données de sous-type en fonction d'une période de temps :
suspend fun deleteExerciseSessionByTimeRange( healthConnectClient: HealthConnectClient, exerciseRecord: ExerciseSessionRecord, ) { val timeRangeFilter = TimeRangeFilter.between(exerciseRecord.startTime, exerciseRecord.endTime) healthConnectClient.deleteRecords(ExerciseSessionRecord::class, timeRangeFilter) // delete the associated distance record healthConnectClient.deleteRecords(DistanceRecord::class, timeRangeFilter) }
Vous pouvez également supprimer les données de sous-type par UID. Cela ne supprime que la session d'exercice, pas les données associées :
suspend fun deleteExerciseSessionByUid( healthConnectClient: HealthConnectClient, exerciseRecord: ExerciseSessionRecord, ) { healthConnectClient.deleteRecords( ExerciseSessionRecord::class, recordIdsList = listOf(exerciseRecord.metadata.id), clientRecordIdsList = emptyList() ) }