הוספת מסלולי אימון

המדריך הזה תואם לגרסה 1.1.0-alpha12 של Health Connect.

מסלולי אימון מאפשרים למשתמשים לעקוב אחרי מסלול GPS של פעילויות אימון משויכות ולשתף מפות של האימונים שלהם עם אפליקציות אחרות.

זמינות התכונות

כדי לברר אם המכשיר של המשתמש תומך במסלולי אימון ב-Health Connect, בודקים את הזמינות של FEATURE_PLANNED_EXERCISE בלקוח:

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

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

מידע נוסף זמין במאמר בדיקת זמינות התכונות.

במדריך הזה מוסבר איך לבקש הרשאות מהמשתמש, וגם איך אפליקציות מקבלות הרשאה לכתוב נתוני מסלול כחלק מאימון.

הפונקציות של קריאה וכתיבה של נתוני מסלולי אימון כוללות:

  1. אפליקציות יוצרות הרשאת כתיבה חדשה למסלולי אימון.
  2. ההוספה מתבצעת על ידי כתיבה של נתוני סשן אימון עם מסלול כשדה שלו.
  3. קריאה:
    1. הבעלים של הסשן יכול לגשת לנתונים באמצעות קריאת סשן.
    2. מתוך אפליקציה של צד שלישי, דרך תיבת דו-שיח שמאפשרת למשתמש להעניק הרשאה לקריאה חד-פעמית של מסלול.

אם למשתמש אין הרשאות כתיבה והמסלול לא מוגדר, המסלול לא מתעדכן.

אם לאפליקציה שלכם יש הרשאת כתיבה של מסלול והיא מנסה לעדכן סשן על ידי העברת אובייקט סשן ללא מסלול, המסלול הקיים נמחק.

הרשאות נדרשות

הגישה למסלול האימון מוגנת על ידי ההרשאות הבאות:

  • android.permission.health.READ_EXERCISE_ROUTE
  • android.permission.health.WRITE_EXERCISE_ROUTE

כדי להוסיף לאפליקציה את האפשרות לשתף מסלולי אימון, צריך קודם לבקש הרשאות כתיבה לסוג הנתונים ExerciseSession.

זו ההרשאה שצריך להצהיר עליה כדי להיות מסוגלים לכתוב מסלול אימון:

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

כדי לקרוא מסלול אימון, צריך לבקש את ההרשאות הבאות:

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

צריך גם להצהיר על הרשאת אימון, כי כל מסלול משויך לסשן אימון (סשן אחד = אימון אחד).

כדי לבקש הרשאות, משתמשים בשיטה PermissionController.createRequestPermissionResultContract() כשמחברים את האפליקציה ל-Health Connect בפעם הראשונה. יש כמה הרשאות שכדאי לבקש:

  • קריאה של נתוני הבריאות, כולל נתוני המסלול: HealthPermission.getReadPermission(ExerciseSessionRecord::class)
  • הרשאה לכתוב נתוני בריאות, כולל נתוני מסלול: HealthPermission.getWritePermission(ExerciseSessionRecord::class)
  • כתיבה של נתוני מסלול האימון: HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE

בקשת הרשאות מהמשתמש

אחרי שיוצרים מופע של לקוח, האפליקציה צריכה לבקש הרשאות מהמשתמש. צריך לאפשר למשתמשים להעניק או לדחות הרשאות בכל שלב.

כדי לעשות זאת, יוצרים קבוצת הרשאות לסוגי הנתונים הנדרשים. קודם צריך לוודא שההרשאות בסט מוצהרות במניפסט של Android.

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

אפשר להשתמש ב-getGrantedPermissions כדי לבדוק אם האפליקציה כבר קיבלה את ההרשאות הנדרשות. אם לא, צריך להשתמש ב-createRequestPermissionResultContract כדי לבקש את ההרשאות האלה. מוצג מסך ההרשאות של Health Connect.

// 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)
  }
}

המשתמשים יכולים לתת או לבטל הרשאות בכל שלב, ולכן האפליקציה צריכה לבדוק מעת לעת אילו הרשאות ניתנו לה, ולטפל בתרחישים שבהם ההרשאה בוטלה.

המידע שכלול ברשומה של אימון

כל רשומה של אימון מכילה את הפרטים הבאים:

  • סוג הפעילות הגופנית, לדוגמה, רכיבה על אופניים.
  • מסלול האימון, שמכיל מידע כמו קו רוחב, קו אורך וגובה.

צבירות נתמכות

אין צבירות נתמכות לסוג הנתונים הזה.

דוגמה לשימוש

לבקש מסלול או לכתוב מסלול מתוך סשן.

בקשת מסלול מסשן

כך קוראים נתונים של אימון ב-Health Connect ושולחים בקשה למסלול מתוך האימון הזה:

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.
    }
  }

כתיבת מסלול מתוך סשן

הקוד הבא מדגים איך לתעד פעילות שכוללת מסלול אימון:

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))
}