Questa guida è compatibile con la versione 1.1.0-alpha11 di Connessione Salute.
Connessione Salute fornisce un tipo di dati esercizio pianificato per consentire alle app di allenamento di scrivere piani di allenamento e alle app di allenamento di leggere i piani di allenamento. Gli esercizi registrati (allenamenti) possono essere riletti per un'analisi personalizzata delle prestazioni per aiutare gli utenti a raggiungere i loro obiettivi di allenamento.
Disponibilità della funzionalità
Per determinare se il dispositivo di un utente supporta i piani di allenamento su Health Connect, controlla la disponibilità diFEATURE_PLANNED_EXERCISE
sul client:
if (healthConnectClient
.features
.getFeatureStatus(
HealthConnectFeatures.FEATURE_PLANNED_EXERCISE
) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {
// Feature is available
} else {
// Feature isn't available
}
Per saperne di più, consulta la sezione Verificare la disponibilità delle funzionalità.
Autorizzazioni richieste
L'accesso all'allenamento pianificato è protetto dalle seguenti autorizzazioni:
android.permission.health.READ_PLANNED_EXERCISE
android.permission.health.WRITE_PLANNED_EXERCISE
Per aggiungere la funzionalità di allenamento pianificato alla tua app, inizia richiedendo le autorizzazioni di scrittura per il tipo di dati PlannedExerciseSession
.
Ecco l'autorizzazione che devi dichiarare per poter scrivere l'allenamento pianificato:
<application>
<uses-permission
android:name="android.permission.health.WRITE_PLANNED_EXERCISE" />
...
</application>
Per leggere l'esercizio pianificato, devi richiedere le seguenti autorizzazioni:
<application>
<uses-permission
android:name="android.permission.health.READ_PLANNED_EXERCISE" />
...
</application>
Richiedere le autorizzazioni all'utente
Dopo aver creato un'istanza client, la tua app deve richiedere le autorizzazioni all'utente. Gli utenti devono poter concedere o negare le autorizzazioni in qualsiasi momento.
A questo scopo, crea un insieme di autorizzazioni per i tipi di dati richiesti. Assicurati che le autorizzazioni nel set siano dichiarate prima nel file manifest di Android.
// Create a set of permissions for required data types
val PERMISSIONS =
setOf(
HealthPermission.getReadPermission(HeartRateRecord::class),
HealthPermission.getWritePermission(HeartRateRecord::class),
HealthPermission.getReadPermission(PlannedExerciseSessionRecord::class),
HealthPermission.getWritePermission(PlannedExerciseSessionRecord::class),
HealthPermission.getReadPermission(ExerciseSessionRecord::class),
HealthPermission.getWritePermission(ExerciseSessionRecord::class)
)
Utilizza getGrantedPermissions
per verificare se la tua app dispone già delle
autorizzazioni richieste. In caso contrario, utilizza
createRequestPermissionResultContract
per richiedere
queste autorizzazioni. Viene visualizzata la schermata delle autorizzazioni di Connessione Salute.
// 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)
}
}
Poiché gli utenti possono concedere o revocare le autorizzazioni in qualsiasi momento, la tua app deve controllare periodicamente le autorizzazioni concesse e gestire gli scenari in cui l'autorizzazione viene persa.
Autorizzazioni correlate
I piani di allenamento sono collegati alle sessioni di allenamento. Pertanto, l'utente deve concedere l'autorizzazione a utilizzare ogni tipo di record correlato a un piano di allenamento per sfruttare appieno questa funzionalità di Connessione Salute.
Ad esempio, se un piano di allenamento misura la frequenza cardiaca di un utente durante una serie di corse, lo sviluppatore potrebbe dover dichiarare le seguenti autorizzazioni e l'utente potrebbe doverle concedere per scrivere la sessione di allenamento e leggere i risultati per una valutazione successiva:
android.permission.health.READ_EXERCISE
android.permission.health.READ_EXERCISE_ROUTES
android.permission.health.READ_HEART_RATE
android.permission.health.WRITE_EXERCISE
android.permission.health.WRITE_EXERCISE_ROUTE
android.permission.health.WRITE_HEART_RATE
Tuttavia, spesso l'app che crea i piani di allenamento e valuta le prestazioni rispetto ai piani non è la stessa che utilizza i piani di allenamento e scrive i dati di allenamento effettivi. A seconda del tipo di app, non saranno necessarie tutte le autorizzazioni di lettura e scrittura. Ad esempio, potresti aver bisogno di queste autorizzazioni per ogni tipo di app:
App per piani di allenamento | App Allenamento |
---|---|
WRITE_PLANNED_EXERCISE |
READ_PLANNED_EXERCISE |
READ_EXERCISE |
WRITE_EXERCISE |
READ_EXERCISE_ROUTES |
WRITE_EXERCISE_ROUTE |
READ_HEART_RATE |
WRITE_HEART_RATE |
Informazioni incluse in un record di sessione di allenamento pianificata
- Titolo della sessione.
- Un elenco di blocchi di allenamento pianificati.
- Ora di inizio e di fine della sessione.
- Tipo di esercizio.
- Note per l'attività.
- Metadati.
- ID sessione di allenamento completata: viene scritto automaticamente al termine di una sessione di allenamento correlata a questa sessione di allenamento pianificata.
Informazioni incluse in un record di blocco di esercizio pianificato
Un blocco di allenamento pianificato contiene un elenco di passaggi di allenamento per supportare la ripetizione di diversi gruppi di passaggi (ad esempio, esegui una sequenza di flessioni per i bicipiti, burpee e crunch cinque volte di seguito).
- Descrizione del blocco.
- Un elenco di passaggi di allenamento pianificati.
- Numero di ripetizioni.
Informazioni incluse in un record di passo di esercizio pianificato
- Descrizione del passaggio.
- Categoria allenamento.
- Tipo di esercizio.
- Un elenco di obiettivi di rendimento.
- Obiettivo di completamento.
Aggregazioni supportate
Non sono presenti aggregazioni supportate per questo tipo di dati.
Esempio di utilizzo
Supponiamo che un utente pianifichi una corsa di 90 minuti tra due giorni. Questa corsa prevede tre giri intorno a un lago con una frequenza cardiaca target compresa tra 90 e 110 battiti al minuto.
- Una sessione di allenamento pianificata con quanto segue è definita dall'utente in
un'app per piani di allenamento:
- Inizio e fine pianificati della corsa
- Il tipo di esercizio (corsa)
- Numero di giri (ripetizioni)
- Obiettivo di rendimento per il battito cardiaco (tra 90 e 110 bpm)
- Queste informazioni vengono raggruppate in blocchi di allenamento e passi e scritte
in Connessione Salute dall'app del piano di allenamento come
PlannedExerciseSessionRecord
. - L'utente esegue la sessione pianificata (in esecuzione).
- I dati di allenamento relativi alla sessione vengono registrati:
- Da un dispositivo indossabile durante la sessione. Ad esempio, il battito cardiaco.
Questi dati vengono scritti in Connessione Salute come tipo di record per l'attività. In questo caso,
HeartRateRecord
. - Manualmente dall'utente dopo la sessione. Ad esempio, indicando
l'inizio e la fine della corsa effettiva. Questi dati vengono scritti in Connessione
Salute come
ExerciseSessionRecord
.
- Da un dispositivo indossabile durante la sessione. Ad esempio, il battito cardiaco.
Questi dati vengono scritti in Connessione Salute come tipo di record per l'attività. In questo caso,
- In un secondo momento, l'app del piano di allenamento legge i dati da Connessione Salute per valutare le prestazioni effettive rispetto agli obiettivi impostati dall'utente nella sessione di allenamento pianificata.
Pianificare gli esercizi e impostare i target
Un utente può pianificare il proprio allenamento in futuro e impostare obiettivi. Scrivi questo in Connessione Salute come sessione di allenamento pianificata.
Nell'esempio descritto in Esempio di utilizzo, l'utente pianifica una corsa di 90 minuti tra due giorni. Questa corsa prevede tre giri intorno a un lago con una frequenza cardiaca target compresa tra 90 e 110 battiti al minuto.
Uno snippet come questo può essere trovato nel gestore di moduli per un'app che registra le sessioni di allenamento pianificate in Connessione Salute. Potrebbe anche trovarsi nel punto di inserimento per le integrazioni, ad esempio con un servizio che offre formazione.
// Verify 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 = ExerciseSegment.EXERCISE_SEGMENT_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,
metadata = Metadata.manualEntry(
device = Device(type = Device.Companion.TYPE_PHONE)
)
)
val insertedPlannedExerciseSessions =
healthConnectClient.insertRecords(listOf(plannedExerciseSessionRecord)).recordIdsList
val insertedPlannedExerciseSessionId = insertedPlannedExerciseSessions.first()
Registrare i dati di attività ed esercizio
Due giorni dopo, l'utente registra la sessione di allenamento effettiva. Scrivi questo dato su Connessione Salute come sessione di allenamento.
In questo esempio, la durata della sessione dell'utente corrisponde esattamente alla durata pianificata.
Il seguente snippet potrebbe essere trovato nel gestore del modulo per un'app che registra sessioni di allenamento in Connessione Salute. Potrebbe essere presente anche nei gestori di importazione ed esportazione dei dati per un dispositivo indossabile in grado di rilevare e registrare le sessioni di allenamento.
insertedPlannedExerciseSessionId
viene riutilizzato dall'esempio precedente. In
un'app reale, l'ID verrebbe determinato dall'utente che seleziona una sessione di allenamento pianificata
da un elenco di sessioni esistenti.
// Verify 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,
metadata = Metadata.manualEntry(
device = Device(type = Device.Companion.TYPE_PHONE)
)
)
val insertedExerciseSessions =
healthConnectClient.insertRecords(listOf(exerciseSessionRecord))
Un dispositivo indossabile registra anche la frequenza cardiaca durante la corsa. Il seguente snippet potrebbe essere utilizzato per generare record all'interno dell'intervallo target.
In un'app reale, le parti principali di questo snippet potrebbero essere trovate nel gestore per un messaggio proveniente da un dispositivo indossabile, che scriverebbe la misurazione in Connessione Salute al momento della raccolta.
// Verify 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,
metadata = Metadata.autoRecorded(
device = Device(type = Device.Companion.TYPE_WATCH)
)
)
val insertedHeartRateRecords = healthConnectClient.insertRecords(listOf(heartRateRecord))
Valutare i target di rendimento
Il giorno dopo l'allenamento dell'utente, puoi recuperare l'esercizio registrato, controllare eventuali target di allenamento pianificati e valutare tipi di dati aggiuntivi per determinare se i target impostati sono stati raggiunti.
Uno snippet come questo si trova probabilmente in un job periodico per valutare i target di rendimento o durante il caricamento di un elenco di esercizi e la visualizzazione di una notifica sui target di rendimento in un'app.
// Verify 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
}
}
}
}
}
}
}
}
Sessioni di allenamento
Le sessioni di allenamento possono includere qualsiasi attività, dalla corsa al badminton.
Scrittura delle sessioni di allenamento
Ecco come creare una richiesta di inserimento che includa una sessione:
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"
),
// ... other records
)
)
}
Lettura di una sessione di allenamento
Ecco un esempio di come leggere una sessione di allenamento:
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
}
}
Scrivere i dati del sottotipo
Le sessioni possono anche essere composte da dati di sottotipo facoltativi, che arricchiscono la sessione con informazioni aggiuntive.
Ad esempio, le sessioni di allenamento possono includere le classi ExerciseSegment
, ExerciseLap
e 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
)