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

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

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"
    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() برمی‌گرداند، می‌توانید کاربر را راهنمایی کنید تا درصورت لزوم Health Connect را از «فروشگاه 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)