พัฒนาประสบการณ์การนอนหลับด้วย Health Connect

หากต้องการสร้างประสบการณ์การติดตามการนอนหลับในแอป คุณสามารถใช้ Health Connect เพื่อทำสิ่งต่างๆ เช่น

  • เขียนข้อมูลเซสชันการนอนหลับ
  • เขียนข้อมูลระยะการนอนหลับ
  • เขียนข้อมูลการนอนหลับ เช่น อัตราการเต้นของหัวใจ ความอิ่มตัวของออกซิเจน และอัตราการหายใจ
  • อ่านข้อมูลการนอนหลับจากแอปอื่นๆ

คู่มือนี้อธิบายวิธีสร้างฟีเจอร์การนอนหลับเหล่านี้ โดยครอบคลุมประเภทข้อมูล การดำเนินการในเบื้องหลัง สิทธิ์ เวิร์กโฟลว์ที่แนะนำ และแนวทางปฏิบัติแนะนำ

ภาพรวม: การสร้างเครื่องมือติดตามการนอนหลับที่ครอบคลุม

คุณสร้างประสบการณ์การติดตามการนอนหลับที่ครอบคลุมได้โดยใช้ Health Connect โดยทำตามขั้นตอนหลักต่อไปนี้

  • การใช้สิทธิ์อย่างถูกต้องตามสิทธิ์ด้านสุขภาพ
  • การบันทึกเซสชันโดยใช้ SleepSessionRecord
  • เขียนประเภทข้อมูล เช่น ระยะการนอนหลับ อัตราการเต้นของหัวใจ และความอิ่มตัวของออกซิเจน อย่างสม่ำเสมอตลอดเซสชัน
  • การจัดการการดำเนินการเบื้องหลังอย่างเหมาะสมเพื่อยืนยันการบันทึกข้อมูลอย่างต่อเนื่อง ตลอดทั้งคืน
  • อ่านข้อมูลเซสชันการอ่านเพื่อดูสรุปและการวิเคราะห์หลังการนอนหลับ

เวิร์กโฟลว์นี้ช่วยให้ทำงานร่วมกับแอป Health Connect อื่นๆ ได้และ ยืนยันการเข้าถึงข้อมูลที่ผู้ใช้ควบคุม

ก่อนเริ่มต้น

ก่อนที่จะใช้ฟีเจอร์การนอนหลับ ให้ทำดังนี้

หัวข้อสำคัญ

Health Connect แสดงข้อมูลการนอนหลับโดยใช้คอมโพเนนต์หลัก 2-3 รายการ A SleepSessionRecord ทำหน้าที่เป็นบันทึกส่วนกลางสำหรับการนอนหลับ ซึ่งมีรายละเอียด เช่น เวลาเริ่มต้นหรือสิ้นสุด และระยะการนอนหลับ ในระหว่างเซสชัน ระบบจะบันทึกข้อมูลประเภทต่างๆ เช่น HeartRateRecord หรือ OxygenSaturationRecord

เซสชันการนอน

ข้อมูลการนอนหลับแสดงโดย SleepSessionRecord แต่ละระเบียนจะจัดเก็บข้อมูลต่อไปนี้

  • startTime
  • endTime
  • stages: รายการSleepSessionRecord.Stage รวมถึงการหลับลึก การหลับตื้น ช่วง REM และการตื่น
  • ข้อมูลเมตาของเซสชันที่ไม่บังคับ (ชื่อ หมายเหตุ)

แอปอาจเขียนข้อมูลหลายประเภทที่เชื่อมโยงกับเซสชัน

ประเภทข้อมูล

ประเภทข้อมูลทั่วไปที่บันทึกระหว่างเซสชันการนอนหลับ ได้แก่

  • SleepSessionRecord: บันทึกระยะเวลาและระยะการนอนหลับ รวมถึง การหลับลึก หลับตื้น ช่วง REM และการตื่น
  • HeartRateRecord: บันทึกอัตราการเต้นของหัวใจขณะหลับ
  • OxygenSaturationRecord: บันทึกความอิ่มตัวของออกซิเจน (SpO2) ระหว่าง การนอนหลับ
  • RespiratoryRateRecord: บันทึกอัตราการหายใจขณะนอนหลับ

ระบบจะจัดเก็บข้อมูลแต่ละประเภทเป็นระเบียนแยกกัน

ข้อควรพิจารณาในการพัฒนา

แอปติดตามการนอนหลับมักจะต้องทำงานเป็นระยะเวลานานๆ และมักจะทำงานในเบื้องหลังเมื่อหน้าจอปิดอยู่ เมื่อสร้างฟีเจอร์การนอนหลับ คุณควรพิจารณาวิธีจัดการการดำเนินการในเบื้องหลังและขอสิทธิ์ที่จำเป็นสำหรับข้อมูลการนอนหลับ

การดำเนินการเมื่ออยู่เบื้องหลัง

โดยปกติแล้วแอปติดตามการนอนหลับจะทำงานตลอดทั้งคืนขณะที่ปิดหน้าจอ ในสถานะนี้ คุณควรใช้สิ่งต่อไปนี้

  • บริการที่ทำงานอยู่เบื้องหน้าสำหรับการเก็บรวบรวมข้อมูล
  • WorkManager สำหรับการเขียนหรือการซิงค์ที่เลื่อนออกไป
  • กลยุทธ์การประมวลผลแบบเป็นชุดสำหรับการเขียนบันทึกปกติของข้อมูลแบบละเอียด เช่น อัตราการเต้นของหัวใจ

รักษาความต่อเนื่องโดยคง ID เซสชันให้สอดคล้องกันในการเขียนทั้งหมด

สิทธิ์

แอปต้องขอสิทธิ์ Health Connect ที่เกี่ยวข้องก่อนอ่านหรือเขียนข้อมูลการนอนหลับ ดูรายการประเภทข้อมูลทั้งหมดได้ที่ประเภทข้อมูล Health Connect สิทธิ์ทั่วไปสำหรับการนอนหลับ ได้แก่ เซสชันการนอนหลับและเมตริก เช่น อัตราการเต้นของหัวใจหรือความอิ่มตัวของออกซิเจน

การเข้าถึงการนอนหลับได้รับการคุ้มครองโดยสิทธิ์ต่อไปนี้

  • 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 manifest ก่อน

val permissions =
    setOf(
        HealthPermission.getReadPermission(SleepSessionRecord::class),
        HealthPermission.getWritePermission(SleepSessionRecord::class),
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class),
        HealthPermission.getReadPermission(OxygenSaturationRecord::class),
        HealthPermission.getWritePermission(OxygenSaturationRecord::class),
        HealthPermission.getReadPermission(RespiratoryRateRecord::class),
        HealthPermission.getWritePermission(RespiratoryRateRecord::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.") }
    }
}
เนื่องจากผู้ใช้สามารถให้หรือเพิกถอนสิทธิ์ได้ทุกเมื่อ แอปของคุณจึงต้อง ตรวจสอบสิทธิ์ทุกครั้งก่อนที่จะใช้สิทธิ์ และจัดการสถานการณ์ที่ สิทธิ์หายไป

ใช้เซสชันการนอนหลับ

ส่วนนี้อธิบายเวิร์กโฟลว์ที่แนะนำสำหรับการบันทึกข้อมูลการนอนหลับ

หากต้องการจัดประเภทข้อมูล เช่น HeartRateRecord หรือ OxygenSaturationRecord ให้สอดคล้องกับเซสชันการนอนหลับ ให้บันทึกข้อมูลดังกล่าวพร้อมการประทับเวลาที่อยู่ระหว่าง startTime และ endTime ของเซสชัน Health Connect ไม่ได้ใช้ตัวระบุเซสชันเพื่อ ลิงก์เซสชันการนอนหลับกับข้อมูลแบบละเอียด แต่การเชื่อมโยงจะเกิดขึ้นโดยนัยผ่าน ช่วงเวลาที่ทับซ้อนกัน เมื่ออ่านข้อมูลการนอนหลับ คุณสามารถใช้ช่วงเวลาของเซสชัน เพื่อค้นหาประเภทข้อมูลที่เชื่อมโยงได้ ดังที่แสดงใน การอ่านข้อมูลการนอนหลับ

เขียนเซสชัน

แม้ว่าระบบจะบันทึกข้อมูลแบบละเอียด เช่น อัตราการเต้นของหัวใจ ตลอดเซสชันการนอนหลับได้ แต่ต้องเขียนข้อมูลSleepSessionRecordการนอนหลับลงใน Health Connect เพียงครั้งเดียวเมื่อเซสชันสิ้นสุดลงแล้ว เช่น เมื่อผู้ใช้ตื่น บันทึกต้องมี เซสชัน startTime, endTime และรายการออบเจ็กต์ SleepSessionRecord.Stage ที่บันทึกไว้ระหว่างเซสชัน เนื่องจาก SleepSessionRecord กำหนดให้ endTime ต้องอยู่หลัง startTime

วิธีเขียนเซสชันการนอนหลับ

  1. สร้างรหัสบันทึกลูกค้าที่ไม่ซ้ำกัน
  2. เมื่อผู้ใช้ตื่นขึ้นหรือหยุดการติดตามการนอนหลับ ให้รวบรวมSleepSessionRecordและสร้างSleepSessionRecord
  3. แทรกระเบียนโดยใช้ insertRecords

ตัวอย่าง

val clientRecordId = UUID.randomUUID().toString()
val sessionStartTime = LocalDateTime.of(2023, 10, 30, 22, 0).toInstant(ZoneOffset.UTC)
val sessionEndTime = LocalDateTime.of(2023, 10, 31, 7, 0).toInstant(ZoneOffset.UTC)

val stages = mutableListOf<SleepSessionRecord.Stage>()
// Add recorded stages, for example:
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(3600),
    endTime = sessionStartTime.plusSeconds(7200),
    stage = SleepSessionRecord.STAGE_TYPE_LIGHT)
)
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(7200),
    endTime = sessionStartTime.plusSeconds(10800),
    stage = SleepSessionRecord.STAGE_TYPE_DEEP)
)
// ... other stages

val session = SleepSessionRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    stages = stages,
    metadata = Metadata(clientRecordId = clientRecordId)
)

healthConnectClient.insertRecords(listOf(session))

การอ่านข้อมูลการนอนหลับ

แอปสามารถอ่านเซสชันการนอนหลับและข้อมูลที่เกี่ยวข้องเพื่อสรุปกิจกรรม ให้ข้อมูลเชิงลึกด้านสุขภาพ หรือซิงค์ข้อมูลกับเซิร์ฟเวอร์ภายนอกได้ ตัวอย่างเช่น คุณ สามารถอ่าน SleepSessionRecord แล้วค้นหา HeartRateRecord ที่เกิดขึ้นในช่วงเวลาเดียวกันนั้น

อ่านเซสชันพร้อมข้อมูลที่เกี่ยวข้อง

คุณอ่านเซสชันการนอนหลับได้โดยใช้ ReadRecordsRequest ที่มี SleepSessionRecord เป็นประเภทบันทึก ซึ่งกรองตามช่วงเวลา หากต้องการอ่านข้อมูลที่เชื่อมโยงสำหรับเซสชันหนึ่งๆ ให้ส่งคำขอที่ 2 สำหรับประเภทข้อมูลที่เลือก เช่น HeartRateRecord—กรองตาม startTime และ endTime ของเซสชันการนอนหลับ

ตัวอย่างต่อไปนี้แสดงวิธีอ่านเซสชันการนอนหลับพร้อมข้อมูลอัตราการเต้นของหัวใจที่เชื่อมโยงสำหรับช่วงเวลาที่กำหนด

suspend fun readSleepSessionsWithAssociatedData(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response = healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = SleepSessionRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )

    for (sleepRecord in response.records) {
        // Process each session
        val stages = sleepRecord.stages
        val notes = sleepRecord.notes

        // To read specific granular data (like heart rate) that occurred during
        // this session, use the session's startTime and endTime to filter
        // the request for that data type.
        val hrResponse = healthConnectClient.readRecords(
            ReadRecordsRequest(
                recordType = HeartRateRecord::class,
                timeRangeFilter = TimeRangeFilter.between(
                    sleepRecord.startTime,
                    sleepRecord.endTime
                )
            )
        )
        for (heartRateRecord in hrResponse.records) {
            for (sample in heartRateRecord.samples) {
                val bpm = sample.beatsPerMinute
            }
        }
    }
}

แนวทางปฏิบัติแนะนำ

โปรดทำตามหลักเกณฑ์ต่อไปนี้เพื่อปรับปรุงความน่าเชื่อถือของข้อมูลและประสบการณ์ของผู้ใช้

  • เขียนบ่อยๆ ระหว่างการติดตามที่ใช้งานอยู่: สำหรับการติดตามที่ใช้งานอยู่ ให้เขียนข้อมูลเมื่อพร้อมใช้งานหรือที่ช่วงเวลาสูงสุด 15 นาที
  • ใช้ WorkManager สำหรับการซิงค์ในเบื้องหลัง: ใช้ WorkManager สำหรับการเขียนที่เลื่อนออกไป ตั้งช่วงเวลา 15 นาทีเพื่อให้ได้สมดุลระหว่างข้อมูลแบบเรียลไทม์และประสิทธิภาพของแบตเตอรี่
  • คำขอเขียนแบบเป็นกลุ่ม: อย่าเขียนเหตุการณ์เซ็นเซอร์แต่ละรายการแยกกัน แบ่งคำขอออกเป็นส่วนๆ Health Connect จัดการบันทึกได้สูงสุด 1,000 รายการต่อคำขอเขียน
  • รักษารหัสเซสชันให้คงที่และไม่ซ้ำกัน: ใช้ตัวระบุที่สอดคล้องกันสำหรับเซสชัน หากมีการแก้ไขหรืออัปเดตเซสชัน การใช้รหัสเดียวกันจะช่วยป้องกันไม่ให้ระบบถือว่าเป็นเซสชันใหม่ที่แยกต่างหาก
  • ใช้การจัดกลุ่มสำหรับประเภทข้อมูล: หากต้องการลดค่าใช้จ่ายอินพุต/เอาต์พุตและรักษาอายุการใช้งานแบตเตอรี่ ให้จัดกลุ่มจุดข้อมูลเป็นinsertRecordsเดียวแทนที่จะเขียนแต่ละจุดแยกกัน
  • หลีกเลี่ยงการเขียนข้อมูลที่ซ้ำกัน: ใช้รหัสไคลเอ็นต์: เมื่อสร้างบันทึก ให้ตั้งค่า metadata.clientRecordId Health Connect จะใช้ค่านี้เพื่อระบุบันทึกที่ไม่ซ้ำกัน หากคุณพยายามเขียนบันทึกที่มี clientRecordId ที่มีอยู่แล้ว Health Connect จะไม่สนใจรายการที่ซ้ำกันหรืออัปเดตบันทึกที่มีอยู่แทนที่จะสร้างบันทึกใหม่ การตั้งค่า metadata.clientRecordId เป็นวิธีที่มีประสิทธิภาพมากที่สุดในการป้องกันรายการที่ซ้ำกันระหว่างการลองซิงค์อีกครั้งหรือการติดตั้งแอปใหม่
    val record = StepsRecord(
        count = 100,
        startTime = startTime,
        endTime = endTime,
        startZoneOffset = ZoneOffset.UTC,
        endZoneOffset = ZoneOffset.UTC,
        metadata = Metadata(
            // Use a unique ID from your own database
            clientRecordId = "daily_steps_2023_10_27_user_123"
        )
    )
  • ตรวจสอบข้อมูลที่มีอยู่: ก่อนซิงค์ ให้ค้นหาระยะเวลาเพื่อดูว่ามีบันทึกจากแอปอยู่แล้วหรือไม่
  • ตรวจสอบว่าการประทับเวลาไม่ทับซ้อนกัน: ตรวจสอบว่าเซสชันใหม่ไม่ได้เริ่มก่อนที่เซสชันก่อนหน้าจะสิ้นสุด เซสชันที่ทับซ้อนกันอาจทำให้เกิดข้อขัดแย้งในแดชบอร์ดฟิตเนสและการคำนวณข้อมูลสรุป
  • ระบุเหตุผลที่ชัดเจนสำหรับสิทธิ์: ใช้โฟลว์ Permission.createIntent เพื่ออธิบายเหตุผลที่แอปของคุณต้องเข้าถึงข้อมูลสุขภาพ เช่น "เพื่อตรวจสอบแนวโน้มความดันโลหิตและให้ข้อมูลเชิงลึก"
  • ทดสอบเซสชันที่ทำงานเป็นเวลานาน: ตรวจสอบการใช้แบตเตอรี่ระหว่างเซสชันที่ใช้เวลาหลายชั่วโมงเพื่อยืนยันว่าช่วงการจัดกลุ่มและการใช้เซ็นเซอร์จะไม่ทำให้แบตเตอรี่ของอุปกรณ์หมดเร็ว
  • จัดแนวการประทับเวลาให้ตรงกับอัตราเซ็นเซอร์: จับคู่การประทับเวลาของบันทึกกับความถี่จริงของเซ็นเซอร์เพื่อรักษาความเที่ยงตรงของข้อมูล

การทดสอบ

โปรดทำตามกลยุทธ์การทดสอบเหล่านี้และดูเอกสารประกอบทดสอบกรณีการใช้งานยอดนิยมอย่างเป็นทางการเพื่อยืนยันความถูกต้องของข้อมูลและประสบการณ์การใช้งานคุณภาพสูง

เครื่องมือยืนยัน

  • กล่องเครื่องมือ Health Connect: ใช้แอปคู่หูนี้เพื่อตรวจสอบระเบียนด้วยตนเอง ลบข้อมูลทดสอบ และจำลองการเปลี่ยนแปลงในฐานข้อมูล ซึ่งเป็น วิธีที่ดีที่สุดในการยืนยันว่าระบบจัดเก็บระเบียนของคุณอย่างถูกต้อง
  • การทำ Unit Test ด้วย FakeHealthConnectClient: ใช้ไลบรารีการทดสอบ เพื่อยืนยันวิธีที่แอปจัดการกรณีขอบ เช่น การเพิกถอนสิทธิ์หรือข้อยกเว้น API โดยไม่ต้องใช้อุปกรณ์จริง

เช็กลิสต์คุณภาพ

สถาปัตยกรรมทั่วไป

การติดตั้งใช้งานการติดตามการนอนหลับมักประกอบด้วยสิ่งต่อไปนี้

ส่วนประกอบ จัดการ
ตัวควบคุมเซสชัน สถานะเซสชัน
ตัวจับเวลา
ตรรกะการจัดกลุ่ม
ตัวควบคุมประเภทข้อมูล
การเก็บรวบรวมข้อมูล
เลเยอร์ที่เก็บ (ครอบคลุมการดำเนินการของ Health Connect) แทรกเซสชัน
แทรกประเภทข้อมูล
แทรกระยะการนอนหลับ
อ่านข้อมูลสรุปเซสชัน
เลเยอร์ UI (การแสดงผล): ระยะเวลา
ประเภทข้อมูลสด
ภาพการนอนหลับ

การแก้ปัญหา

ลักษณะปัญหา สาเหตุที่เป็นไปได้ ความละเอียด
ประเภทข้อมูลที่ขาดหายไป (เช่น อัตราการเต้นของหัวใจ) ไม่มีสิทธิ์เขียนหรือตัวกรองเวลาไม่ถูกต้อง ตรวจสอบว่าคุณได้ขอและผู้ใช้ได้ให้สิทธิ์ประเภทข้อมูลที่เฉพาะเจาะจงแล้ว ตรวจสอบว่า ReadRecordsRequest ใช้ TimeRangeFilter ที่ตรงกับเซสชัน ดูสิทธิ์
เซสชันเขียนไม่สำเร็จ การประทับเวลาที่ซ้อนทับกัน Health Connect อาจปฏิเสธบันทึกที่ทับซ้อนกับข้อมูลที่มีอยู่จากแอปเดียวกัน ตรวจสอบว่าstartTimeของเซสชันใหม่เกิดขึ้นหลังจากendTimeของเซสชันก่อนหน้า
ไม่มีการบันทึกข้อมูลเซ็นเซอร์ขณะนอนหลับ บริการที่ทำงานอยู่เบื้องหน้าถูกหยุดทำงานหรือไม่ทำงาน หากต้องการรวบรวมข้อมูลเซ็นเซอร์ข้ามคืนขณะที่หน้าจอปิดอยู่ คุณสามารถใช้บริการที่ทำงานอยู่เบื้องหน้ากับ foregroundServiceType="health" ได้
ระเบียนที่ซ้ำกันปรากฏขึ้น ไม่มี clientRecordId กำหนด clientRecordId ที่ไม่ซ้ำกันใน Metadata ของแต่ละระเบียน ซึ่งจะช่วยให้ Health Connect สามารถขจัดข้อมูลที่ซ้ำกันได้หากมีการเขียนข้อมูลเดียวกัน 2 ครั้งระหว่างการลองซิงค์อีกครั้ง ดูแนวทางปฏิบัติแนะนำ

ขั้นตอนการแก้ไขข้อบกพร่องที่พบบ่อย

ตรวจสอบสถานะสิทธิ์ โปรดเรียกใช้ getPermissionStatus() เสมอก่อนที่จะพยายามดำเนินการอ่านหรือเขียน ผู้ใช้สามารถเพิกถอนสิทธิ์ในการตั้งค่าระบบได้ทุกเมื่อ
ยืนยันโหมดการดำเนินการ หากแอปไม่ได้รวบรวมข้อมูลในเบื้องหลัง ให้ตรวจสอบว่าคุณได้ประกาศสิทธิ์ที่ถูกต้องในไฟล์ AndroidManifest.xml และผู้ใช้ไม่ได้ตั้งค่าแอปเป็นโหมด "จำกัดแบตเตอรี่"