إضافة مسارات التمارين الرياضية

يتوافق هذا الدليل مع الإصدار 1.1.0-alpha12 من Health Connect.

تتيح مسارات التمارين الرياضية للمستخدمين تتبُّع مسار نظام تحديد المواقع العالمي (GPS) لأنشطة التمارين المقترنة ومشاركة خرائط تمارينهم الرياضية مع تطبيقات أخرى.

يوفّر هذا الدليل معلومات عن كيفية طلب الأذونات من المستخدم، ويوضّح أيضًا كيفية حصول التطبيقات على إذن لكتابة بيانات المسار كجزء من جلسة التمارين.

في ما يلي ملخّص موجز لوظيفة القراءة والكتابة لمسارات التمارين الرياضية:

  1. تنشئ التطبيقات إذن كتابة جديدًا لمسارات التمارين الرياضية.
  2. تتم عملية الإدراج من خلال كتابة جلسة تمرين مع مسار كحقل لها.
  3. القراءة:
    1. بالنسبة إلى مالك الجلسة، يتم الوصول إلى البيانات باستخدام عملية قراءة الجلسة.
    2. من تطبيق تابع لجهة خارجية، من خلال مربّع حوار يتيح للمستخدم منح إذن قراءة مسار لمرة واحدة

طلب الأذونات من المستخدم

بعد إنشاء مثيل عميل، يجب أن يطلب تطبيقك الأذونات من العميل. يجب السماح للمستخدمين بمنح الأذونات أو رفضها في أي وقت.

لإجراء ذلك، أنشئ مجموعة من الأذونات لأنواع البيانات المطلوبة. تأكَّد من أنّ الأذونات في المجموعة مُدرَجة في بيان 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)
  }
}

بما أنّه يمكن للمستخدمين منح الأذونات أو إبطالها في أي وقت، يجب أن يتحقق تطبيقك باستمرار من الأذونات الممنوحة ويتعامل مع السيناريوهات التي يتم فيها فقدان الإذن.

أذونات قراءة وكتابة مسارات التمارين الرياضية

تملك مسارات التمارين الرياضية إذن كتابة وقت التشغيل الخاص بها (android.permission.health.WRITE_EXERCISE_ROUTE).

لإضافة ميزة مسار التمرين إلى تطبيقك، ابدأ بطلب أذونات كتابة لنوع بيانات معيّن.

عليك أيضًا الإفصاح عن إذن ممارسة الرياضة، لأنّ كل مسار مرتبط بجلسة تمرين (جلسة واحدة = تمرين واحد).

في ما يلي الإذن الذي يجب الإفصاح عنه لتتمكّن من كتابة مسارات التمارين الرياضية:

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

لقراءة مسارات التمارين الرياضية، عليك طلب الأذونات التالية:

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

لطلب الأذونات، استخدِم PermissionController.createRequestPermissionResultContract() عند ربط تطبيقك بتطبيق Health Connect لأول مرة. في ما يلي العديد من الأذونات التي قد تحتاج إلى طلبها:

  • قراءة البيانات الصحية، بما في ذلك بيانات المسار: HealthPermission.getReadPermission(ExerciseSessionRecord::class)
  • كتابة بيانات الصحة، بما في ذلك بيانات المسار: HealthPermission.getWritePermission(ExerciseSessionRecord::class)
  • كتابة بيانات مسار التمرين الرياضي: HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE

قراءة بيانات المسار وكتابتها

تُدخِل التطبيقات مسارًا من خلال كتابة جلسة تتضمّن مسارًا كحقل.

إذا لم يكن لدى المستخدم أذونات للكتابة ولم يتم ضبط المسار، لن يتم تعديل المسار.

إذا كان تطبيقك يملك إذن كتابة مسار وحاول تعديل جلسة من خلال إدخال عنصر جلسة بدون مسار، يتم حذف المسار الحالي.

عندما يحتاج تطبيقك إلى قراءة بيانات المسار المقدَّمة من تطبيق تابع لجهة خارجية، يظهر مربع diálogo يطلب من المستخدم السماح بعملية القراءة.

طلب مسار من جلسة

في ما يلي كيفية قراءة جلسة في 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))
}