ردیابی جلسه‌های خواب

این راهنما با نسخه 1.1.0-alpha11 از Health Connect سازگار است.

‫Health Connect نوع داده جلسه خواب را برای ذخیره اطلاعات مربوط به خواب کاربر، مثل جلسه خواب شبانه یا خواب روزانه، ارائه می‌دهد. از نوع داده SleepSessionRecord برای نمایش این جلسه‌ها استفاده می‌شود.

جلسه‌ها به کاربران امکان می‌دهد عملکرد مبتنی بر زمان را در یک دوره زمانی اندازه‌گیری کنند، مثل داده‌های مکان یا ضربان قلب پیوسته.

‫SleepSessionRecord جلسه حاوی داده‌هایی است که مراحل خواب را ثبت می‌کند، مثل AWAKE،‏ SLEEPING، و DEEP.

داده‌های زیرنوع داده‌هایی هستند که «متعلق به» یک جلسه هستند و فقط زمانی معنی‌دار هستند که با جلسه والد خوانده شوند. برای مثال، مرحله خواب.

از سوی دیگر، داده‌های منسوب به داده‌هایی اشاره دارد که به‌طور مستقل ثبت می‌شوند اما در محدوده زمانی یک جلسه قرار می‌گیرند. برای مثال، اگر کاربری «ضربان قلب» را درطول جلسه خواب خود ضبط کند، داده‌های «ضربان قلب» داده‌های مرتبط خواهد بود. برخلاف داده‌های زیرنوع که بخشی از گزارش جلسه است، داده‌های منسوب از گزارش‌های مستقل تشکیل شده است که هرکدام شناسه UUID خود را دارند.

بررسی دردسترس بودن 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» نصب یا به‌روزرسانی کند.

دردسترس بودن ویژگی

پرچم دردسترس بودن ویژگی برای این نوع داده وجود ندارد.

مجوزهای لازم

دسترسی به جلسه خواب با اجازه‌های زیر محافظت می‌شود:

  • android.permission.health.READ_SLEEP
  • android.permission.health.WRITE_SLEEP

برای افزودن قابلیت جلسه خواب به برنامه‌تان، ابتدا اجازه‌های نوع داده SleepSession را درخواست کنید.

برای اینکه بتوانید جلسه خواب بنویسید، باید اجازه زیر را اعلام کنید:

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

برای خواندن جلسه خواب، باید اجازه‌های زیر را درخواست کنید:

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

درخواست اجازه‌ها از کاربر

پس‌از ایجاد نمونه کارخواه، برنامه شما باید از کاربر اجازه درخواست کند. کاربران باید بتوانند در هر زمانی اجازه‌ها را اعطا یا رد کنند. برای انجام این کار، مجموعه‌ای از اجازه‌ها را برای انواع داده موردنیاز ایجاد کنید. ابتدا مطمئن شوید که اجازه‌های موجود در مجموعه در مانیفست Android شما اعلام شده باشد.

val permissions =
    setOf(
        HealthPermission.getReadPermission(SleepSessionRecord::class),
        HealthPermission.getWritePermission(SleepSessionRecord::class)
    )
از getGrantedPermissions استفاده کنید تا ببینید آیا برنامه شما ازقبل اجازه‌های لازم را دارد یا نه. درغیراین‌صورت، از createRequestPermissionResultContract برای درخواست این اجازه‌ها استفاده کنید. با این کار، صفحه اجازه‌های Health Connect نمایش داده می‌شود.
val permissions = setOf(
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class),
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class)
    )

val requestPermissionsLauncher = rememberLauncherForActivityResult(
    contract = PermissionController.createRequestPermissionResultContract()
) { grantedPermissions ->
    if (grantedPermissions.containsAll(permissions)) {
        coroutineScope.launch { snackbarHostState.showSnackbar("Permissions granted!") }
    } else {
        coroutineScope.launch { snackbarHostState.showSnackbar("Permissions denied.") }
    }
}
ازآنجایی‌که کاربران می‌توانند در هر زمانی اجازه‌ها را اعطا یا لغو کنند، برنامه شما باید هر بار قبل‌از استفاده از اجازه‌ها، آن‌ها را بررسی کند و سناریوهایی را که اجازه ازدست می‌رود مدیریت کند.

تجمع‌های پشتیبانی‌شده

مقادیر تجمیعی زیر برای SleepSessionRecord دردسترس است:

راهنمای عمومی

در اینجا چند دستورالعمل روال مطلوب درباره نحوه کار با جلسات خواب در Health Connect ارائه شده است.

  • از جلسه‌ها باید برای افزودن داده‌های جلسه خواب خاصی استفاده شود، برای خواب:

suspend fun writeSleepSession(healthConnectClient: HealthConnectClient) {
    healthConnectClient.insertRecords(
        listOf(
            SleepSessionRecord(
                startTime = Instant.parse("2022-05-10T23:00:00.000Z"),
                startZoneOffset = ZoneOffset.of("-08:00"),
                endTime = Instant.parse("2022-05-11T07:00:00.000Z"),
                endZoneOffset = ZoneOffset.of("-08:00"),
                title = "My Sleep",
                metadata = Metadata.activelyRecorded(device = Device(type = Device.TYPE_WATCH))
            ),
        )
    )
}

  • داده‌های نوع فرعی باید در جلسه‌ای با مُهرهای زمان متوالی که هم‌پوشانی ندارند تراز شوند. بااین‌حال، فاصله‌ها مجاز است.
  • داده‌های زیرنوع حاوی UUID نیست، اما داده‌های مرتبط دارای UUIDهای متمایز است.
  • جلسه‌ها زمانی مفید هستند که کاربر بخواهد داده‌ها با جلسه مرتبط شوند (و به‌عنوان بخشی از جلسه ردیابی شوند)، نه اینکه به‌طور مداوم ضبط شوند.

جلسه‌های خواب

می‌توانید داده‌های خواب را در Health Connect بخوانید یا بنویسید. داده‌های خواب به‌صورت جلسه نمایش داده می‌شود و می‌تواند به ۸ مرحله خواب مجزا تقسیم شود:

  • ‫UNKNOWN: اگر کاربر خواب باشد، مشخص‌نشده یا ناشناس است.
  • AWAKE: کاربر درطول چرخه خواب بیدار است، نه درطول روز.
  • ‫SLEEPING: شرح خواب کلی یا غیرجزئی.
  • OUT_OF_BED: کاربر در میان جلسه خواب از تخت‌خواب بلند می‌شود.
  • ‫AWAKE_IN_BED: کاربر در تخت‌خواب بیدار است.
  • ‫LIGHT: کاربر در چرخه خواب سبک است.
  • ‫DEEP: کاربر در چرخه خواب عمیق است.
  • ‫REM: کاربر در چرخه خواب REM است.

این مقادیر نشان‌دهنده نوع خوابی است که کاربر در یک محدوده زمانی تجربه می‌کند. نوشتن مراحل خواب اختیاری است، اما درصورت دردسترس بودن توصیه می‌شود.

نوشتن داده‌های جلسه خواب

نوع داده SleepSessionRecord دو بخش دارد:

  1. کل جلسه که کل مدت خواب را دربرمی‌گیرد.
  2. مراحل جداگانه درطول جلسه خواب مانند خواب سبک یا خواب عمیق.

در اینجا نحوه درج جلسه خواب بدون مراحل آورده شده است:

val zoneRules = ZoneId.systemDefault().rules

// Calculate the specific offset for both start and end times
val startOffset = zoneRules.getOffset(startTime)
val endOffset = zoneRules.getOffset(endTime)

SleepSessionRecord(
    title = "weekend sleep",
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = startOffset,
    endZoneOffset = endOffset,
    metadata = Metadata.activelyRecorded(device = Device(type = Device.TYPE_WATCH))
)

در اینجا نحوه افزودن مراحلی که کل دوره جلسه خواب را پوشش می‌دهد آورده شده است:

val stages = listOf(
    SleepSessionRecord.Stage(
        startTime = START_TIME,
        endTime = END_TIME,
        stage = SleepSessionRecord.STAGE_TYPE_SLEEPING,
    )
)

SleepSessionRecord(
        title = "weekend sleep",
        startTime = START_TIME,
        endTime = END_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endZoneOffset = END_ZONE_OFFSET,
        stages = stages,
)

خواندن جلسه خواب

برای هر جلسه خواب برگشتی، باید بررسی کنید که آیا داده‌های مرحله خواب نیز وجود دارد یا خیر:

val response =
    healthConnectClient.readRecords(
        ReadRecordsRequest(
            SleepSessionRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
for (sleepRecord in response.records) {
    // Retrieve relevant sleep stages from each sleep record
    val sleepStages = sleepRecord.stages
}

حذف جلسه خواب

به این صورت می‌توانید جلسه را حذف کنید. برای این مثال، از جلسه خواب استفاده کرده‌ایم:

val timeRangeFilter = TimeRangeFilter.between(sleepRecord.startTime, sleepRecord.endTime)
healthConnectClient.deleteRecords(SleepSessionRecord::class, timeRangeFilter)