कसरत के रूट जोड़ें

यह गाइड, Health Connect के 1.1.0-alpha12 वर्शन के साथ काम करती है.

कसरत के रूट की मदद से, उपयोगकर्ता कसरत से जुड़ी गतिविधियों के लिए जीपीएस रूट को ट्रैक कर सकते हैं. साथ ही, अपने वर्कआउट के मैप को अन्य ऐप्लिकेशन के साथ शेयर कर सकते हैं.

इस गाइड में, उपयोगकर्ता से अनुमतियां मांगने का तरीका बताया गया है. इसमें यह भी बताया गया है कि कसरत के सेशन के दौरान, ऐप्लिकेशन को रास्ते का डेटा लिखने की अनुमति कैसे मिलती है.

कसरत के रूट से जुड़ा डेटा पढ़ने और लिखने की सुविधा में ये शामिल हैं:

  1. ऐप्लिकेशन, कसरत के रास्तों के लिए नई अनुमति बनाते हैं.
  2. रूट को फ़ील्ड के तौर पर इस्तेमाल करके, कसरत के सेशन की जानकारी डाली जाती है.
  3. पढ़ना:
    1. सेशन के मालिक के लिए, सेशन रीड का इस्तेमाल करके डेटा ऐक्सेस किया जाता है.
    2. किसी तीसरे पक्ष के ऐप्लिकेशन से, ऐसे डायलॉग के ज़रिए जिसमें उपयोगकर्ता को किसी रूट को एक बार पढ़ने की अनुमति देने का विकल्प मिलता है.

अगर उपयोगकर्ता के पास लिखने की अनुमतियां नहीं हैं और रास्ता सेट नहीं है, तो रास्ता अपडेट नहीं होता.

अगर आपके ऐप्लिकेशन के पास रूट की जानकारी लिखने की अनुमति है और वह रूट की जानकारी के बिना सेशन ऑब्जेक्ट पास करके किसी सेशन को अपडेट करने की कोशिश करता है, तो मौजूदा रूट की जानकारी मिटा दी जाती है.

देखें कि Health Connect उपलब्ध है या नहीं

Health Connect का इस्तेमाल करने से पहले, आपके ऐप्लिकेशन को यह पुष्टि करनी चाहिए कि Health Connect, उपयोगकर्ता के डिवाइस पर उपलब्ध है. ऐसा हो सकता है कि Health Connect, सभी डिवाइसों पर पहले से इंस्टॉल न हो या इसे बंद कर दिया गया हो. HealthConnectClient.getSdkStatus() तरीके का इस्तेमाल करके, यह देखा जा सकता है कि कोई सुविधा उपलब्ध है या नहीं.

Health Connect की उपलब्धता की जांच करने का तरीका

fun checkHealthConnectAvailability(context: Context) {
    val providerPackageName = "com.google.android.apps.healthdata" // Or get from HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME
    val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName)

    if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
      // Health Connect is not available. Guide the user to install/enable it.
      // For example, show a dialog.
      return // early return as there is no viable integration
    }
    if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
      // Health Connect is available but requires an update.
      // Optionally redirect to package installer to find a provider, for example:
      val uriString = "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding"
      context.startActivity(
        Intent(Intent.ACTION_VIEW).apply {
          setPackage("com.android.vending")
          data = Uri.parse(uriString)
          putExtra("overlay", true)
          putExtra("callerId", context.packageName)
        }
      )
      return
    }
    // Health Connect is available, obtain a HealthConnectClient instance
    val healthConnectClient = HealthConnectClient.getOrCreate(context)
    // Issue operations with healthConnectClient
}

getSdkStatus() से मिले स्टेटस के आधार पर, उपयोगकर्ता को Google Play Store से Health Connect इंस्टॉल या अपडेट करने के लिए कहा जा सकता है.

सुविधा की उपलब्धता

यह पता लगाने के लिए कि उपयोगकर्ता के डिवाइस पर 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
}
ज़्यादा जानने के लिए, सुविधा की उपलब्धता की जांच करना लेख पढ़ें.

ज़रूरी अनुमतियां

कसरत के रूट को ऐक्सेस करने की सुविधा, इन अनुमतियों के तहत सुरक्षित रखी जाती है:

  • android.permission.health.READ_EXERCISE_ROUTES
  • android.permission.health.WRITE_EXERCISE_ROUTE
ध्यान दें: इस तरह की अनुमति के लिए, READ_EXERCISE_ROUTES बहुवचन है, जबकि 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_ROUTES" />
...
</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)
  }
}

उपयोगकर्ता किसी भी समय अनुमतियां दे सकते हैं या उन्हें रद्द कर सकते हैं. इसलिए, आपके ऐप्लिकेशन को समय-समय पर यह जांच करनी चाहिए कि कौनसी अनुमतियां दी गई हैं. साथ ही, उन स्थितियों को मैनेज करना चाहिए जिनमें अनुमति नहीं दी गई है.

एक्सरसाइज़ सेशन के रिकॉर्ड में शामिल जानकारी

एक्सरसाइज़ के हर सेशन के रिकॉर्ड में यह जानकारी शामिल होती है:

  • कसरत का टाइप. उदाहरण के लिए, साइकल चलाना.
  • कसरत का रास्ता, जिसमें अक्षांश, देशांतर, और ऊंचाई जैसी जानकारी शामिल होती है.

इस्तेमाल किए जा सकने वाले एग्रीगेशन

ExerciseSessionRecord के लिए, ये एग्रीगेट वैल्यू उपलब्ध हैं:

इस्तेमाल का उदाहरण

यहां दिए गए कोड स्निपेट में, कसरत के रास्ते को पढ़ने और लिखने का तरीका बताया गया है.

कसरत का रूट देखें

बैकग्राउंड में चलने पर, आपका ऐप्लिकेशन अन्य ऐप्लिकेशन से बनाए गए कसरत के रूट का डेटा नहीं पढ़ सकता.

जब आपका ऐप्लिकेशन बैकग्राउंड में चलता है और किसी दूसरे ऐप्लिकेशन से बनाए गए कसरत के रूट को पढ़ने की कोशिश करता है, तो Health Connect एक ExerciseRouteResult.ConsentRequiredजवाब देता है. भले ही, आपके ऐप्लिकेशन के पास कसरत के रूट के डेटा को हमेशा अनुमति दें का ऐक्सेस हो.

इस वजह से, हमारा सुझाव है कि आप उपयोगकर्ता के ऐप्लिकेशन के साथ इंटरैक्ट करने पर ही रास्तों के लिए अनुरोध करें. ऐसा तब करें, जब उपयोगकर्ता आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) का इस्तेमाल कर रहा हो.

बैकग्राउंड में डेटा पढ़ने की सुविधा के बारे में ज़्यादा जानने के लिए, बैकग्राउंड में डेटा पढ़ने की सुविधा का उदाहरण देखें.

नीचे दिए गए कोड स्निपेट में, 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))
}

कसरत के सेशन

एक्सरसाइज़ सेशन में, दौड़ने से लेकर बैडमिंटन खेलने तक कुछ भी शामिल हो सकता है.

कसरत के सेशन का डेटा सेव करने की अनुमति दें

सेशन शामिल करने का अनुरोध इस तरह बनाया जाता है:

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

कसरत के सेशन का डेटा पढ़ने की अनुमति दें

यहां कसरत के सेशन को पढ़ने का तरीका बताया गया है:

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

सबटाइप का डेटा लिखने की अनुमति

सेशन में, वैकल्पिक सबटाइप डेटा भी शामिल हो सकता है. इससे सेशन में ज़्यादा जानकारी मिलती है.

उदाहरण के लिए, कसरत वाले सेशन में ExerciseSegment, ExerciseLap, और 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
)

कसरत का कोई सेशन मिटाना

एक्सरसाइज़ सेशन को मिटाने के दो तरीके हैं:

  1. समयसीमा के हिसाब से.
  2. यूआईडी के हिसाब से.

यहां समयसीमा के हिसाब से सबटाइप का डेटा मिटाने का तरीका बताया गया है:

suspend fun deleteExerciseSessionByTimeRange(
    healthConnectClient: HealthConnectClient,
    exerciseRecord: ExerciseSessionRecord,
) {
    val timeRangeFilter = TimeRangeFilter.between(exerciseRecord.startTime, exerciseRecord.endTime)
    healthConnectClient.deleteRecords(ExerciseSessionRecord::class, timeRangeFilter)
    // delete the associated distance record
    healthConnectClient.deleteRecords(DistanceRecord::class, timeRangeFilter)
}

यूआईडी के हिसाब से भी सबटाइप का डेटा मिटाया जा सकता है. ऐसा करने से सिर्फ़ कसरत का सेशन मिटता है, उससे जुड़ा डेटा नहीं:

suspend fun deleteExerciseSessionByUid(
    healthConnectClient: HealthConnectClient,
    exerciseRecord: ExerciseSessionRecord,
) {
    healthConnectClient.deleteRecords(
        ExerciseSessionRecord::class,
        recordIdsList = listOf(exerciseRecord.metadata.id),
        clientRecordIdsList = emptyList()
    )
}