Aggiungi percorsi per l'esercizio fisico

Questa guida è compatibile con la versione 1.1.0-alpha12 di Connessione Salute.

I percorsi di allenamento consentono agli utenti di monitorare un percorso GPS per le attività fisiche associate e condividere le mappe dei loro allenamenti con altre app.

Questa guida fornisce informazioni su come richiedere le autorizzazioni all'utente e illustra anche come le app ricevono l'autorizzazione a scrivere i dati del percorso nell'ambito di una sessione di allenamento.

Ecco un breve riepilogo delle funzionalità di lettura e scrittura per i percorsi degli allenamenti:

  1. Le app creano una nuova autorizzazione di scrittura per i percorsi degli esercizi.
  2. L'inserimento avviene scrivendo una sessione di allenamento con un percorso come campo.
  3. Lettura:
    1. Per il proprietario della sessione, i dati vengono letti utilizzando una lettura della sessione.
    2. Da un'app di terze parti, tramite una finestra di dialogo che consente all'utente di concedere una lettura una tantum di un itinerario.

Richiedi le autorizzazioni all'utente

Dopo aver creato un'istanza client, l'app deve richiedere all'utente le autorizzazioni. Gli utenti devono poter concedere o negare le autorizzazioni in qualsiasi momento.

A tale scopo, crea un insieme di autorizzazioni per i tipi di dati richiesti. Assicurati innanzitutto che le autorizzazioni nel set siano dichiarate nel file manifest di Android.

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(ExerciseSessionRecord::class),
  HealthPermission.getWritePermission(ExerciseSessionRecord::class)
)

Utilizza getGrantedPermissions per verificare se alla tua app sono già state concesse le autorizzazioni richieste. In caso contrario, usa createRequestPermissionResultContract per richiedere quelle 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 di scrittura e lettura dei percorsi degli esercizi

I percorsi degli esercizi hanno la propria autorizzazione di scrittura di runtime (android.permission.health.WRITE_EXERCISE_ROUTE).

Per aggiungere la funzionalità di percorso dell'allenamento alla tua app, inizia richiedendo le autorizzazioni di scrittura per un tipo di dati specifico.

Devi anche dichiarare un'autorizzazione per l'allenamento, poiché ogni percorso è associato a una sessione di allenamento (una sessione = un allenamento).

Ecco l'autorizzazione che devi dichiarare per poter scrivere percorsi di allenamento:

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

Per leggere i percorsi degli esercizi, devi richiedere le seguenti autorizzazioni:

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

Per richiedere le autorizzazioni, utilizza il metodo PermissionController.createRequestPermissionResultContract() la prima volta che colleghi la tua app a Connessione Salute. Ecco alcune autorizzazioni che potresti voler richiedere:

  • Leggere i dati sanitari, inclusi i dati sui percorsi: HealthPermission.getReadPermission(ExerciseSessionRecord::class)
  • Scrivere dati sanitari, inclusi i dati relativi al percorso: HealthPermission.getWritePermission(ExerciseSessionRecord::class)
  • Scrittura dei dati relativi al percorso dell'allenamento: HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE

Leggere e scrivere dati sui percorsi

Le app inseriscono una route scrivendo una sessione con una route come campo.

Se l'utente non dispone delle autorizzazioni di scrittura e il percorso non è impostato, il percorso non viene aggiornato.

Se la tua app dispone di un'autorizzazione di scrittura della route e tenta di aggiornare una sessione passando un oggetto sessione senza una route, la route esistente viene eliminata.

Ogni volta che la tua app deve leggere i dati del percorso forniti da un'app di terze parti, viene visualizzata una finestra di dialogo che chiede all'utente di consentire l'operazione di lettura.

Richiedere un itinerario da una sessione

Ecco come leggere una sessione in Connessione Salute e richiedere un itinerario da quella sessione:

suspend fun readExerciseSessionAndRoute() {
    val endTime = Instant.now()
    val startTime = endTime.minus(Duration.ofHours(1))

    val grantedPermissions =
        healthConnectClient.permissionController.getGrantedPermissions()
    if (!grantedPermissions.contains(
          HealthPermission.getReadPermission(ExerciseSessionRecord::class))) {
        // The user doesn't allow the app to read exercise session data.
        return
    }

    val readResponse =
      healthConnectClient.readRecords(
        ReadRecordsRequest(
          ExerciseSessionRecord::class,
          TimeRangeFilter.between(startTime, endTime)
        )
      )
    val exerciseRecord = readResponse.records.first()
    val recordId = exerciseRecord.metadata.id

    // See https://developer.android.com/training/basics/intents/result#launch
    // for appropriately handling ActivityResultContract.
    val requestExerciseRouteLauncher = fragment.registerForActivityResul
    (ExerciseRouteRequestContract()) { exerciseRoute: ExerciseRoute? ->
            if (exerciseRoute != null) {
                displayExerciseRoute(exerciseRoute)
            } else {
                // Consent was denied
            }
        }

    val exerciseSessionRecord =
      healthConnectClient.readRecord(ExerciseSessionRecord::class, recordId).record

    when (val exerciseRouteResult = exerciseSessionRecord.exerciseRouteResult) {
        is ExerciseRouteResult.Data ->
            displayExerciseRoute(exerciseRouteResult.exerciseRoute)
        is ExerciseRouteResult.ConsentRequired ->
            requestExerciseRouteLauncher.launch(recordId)
        is ExerciseRouteResult.NoData -> Unit // No exercise route to show
        else -> Unit
    }
  }

  fun displayExerciseRoute(route: ExerciseRoute?) {
    val locations = route.route.orEmpty()
    for (location in locations) {
      // Handle location.
    }
  }

Scrivere un percorso da una sessione

Il seguente codice mostra come registrare una sessione che include un percorso di esercizio:

suspend fun InsertExerciseRoute(healthConnectClient: HealthConnectClient) {
    val grantedPermissions =
        healthConnectClient.permissionController.getGrantedPermissions()
    if (!grantedPermissions.contains(
          getWritePermission(ExerciseSessionRecord::class))) {
        // The user doesn't allow the app to write exercise session data.
        return
    }

    val sessionStartTime = Instant.now()
    val sessionDuration = Duration.ofMinutes(20)
    val sessionEndTime = sessionStartTime.plus(sessionDuration)

    val exerciseRoute =
        if (grantedPermissions.contains(PERMISSION_WRITE_EXERCISE_ROUTE)) ExerciseRoute(
            listOf(
                ExerciseRoute.Location(
                    // Location times must be on or after the session start time
                    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(
                    // Location times must be before the session end time
                    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
        // The user doesn't allow the app to write exercise route data.
            null
    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.manualEntry(
            device = Device(type = Device.TYPE_PHONE)
        ),
    )
    val response = healthConnectClient.insertRecords(listOf(exerciseSessionRecord))
}