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

يتوافق هذا الدليل مع الإصدار 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))
}