แอปที่เปิดตลอดเวลาและโหมดแอมเบียนท์ของระบบ

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

การทำให้แอปมองเห็นได้ตลอดเวลาจะส่งผลต่อระยะเวลาการใช้งานแบตเตอรี่อย่างมาก ดังนั้นโปรดพิจารณา ผลกระทบด้านพลังงานเมื่อเพิ่มฟีเจอร์นี้

หัวข้อสำคัญ

เมื่อแอป Wear OS แสดงแบบเต็มหน้าจอ แอปจะอยู่ในสถานะพลังงาน 2 สถานะต่อไปนี้

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

ระบบปฏิบัติการจะควบคุมการเปลี่ยนสถานะระหว่างสถานะเหล่านี้

แอปที่เปิดตลอดเวลาคือแอปพลิเคชันที่แสดงเนื้อหาทั้งในสถานะโต้ตอบและแอมเบียนท์

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

การเปลี่ยนระบบและลักษณะการทำงานเริ่มต้น

เมื่อแอปอยู่เบื้องหน้า ระบบจะจัดการการเปลี่ยนสถานะพลังงาน ตามการหมดเวลา 2 รายการที่ทริกเกอร์จากการที่ผู้ใช้ไม่มีกิจกรรม

  • หมดเวลา #1: สถานะโต้ตอบเป็นสถานะแวดล้อม: หลังจากที่ผู้ใช้ไม่ได้ใช้งานเป็นระยะเวลาหนึ่ง อุปกรณ์จะเข้าสู่สถานะแวดล้อม
  • หมดเวลา #2: กลับไปที่หน้าปัด: หลังจากไม่มีการใช้งานอีกระยะหนึ่ง ระบบอาจซ่อนแอปปัจจุบันและแสดงหน้าปัด

ทันทีหลังจากที่ระบบเปลี่ยนสถานะครั้งแรกเป็นสถานะรอบข้าง ลักษณะการทำงานเริ่มต้นจะขึ้นอยู่กับเวอร์ชัน Wear OS และการกำหนดค่าของแอป ดังนี้

  • ใน Wear OS 5 และเวอร์ชันที่ต่ำกว่า ระบบจะแสดงภาพหน้าจอที่เบลอของแอปพลิเคชันที่หยุดชั่วคราว โดยมีเวลาซ้อนทับอยู่ด้านบน สถานะนี้แสดงโดยโหนด "AOD Lite" ในโฟลว์ชาร์ตต่อไปนี้
  • ใน Wear OS 6 ขึ้นไป หากแอปกำหนดเป้าหมายเป็น SDK 36 ขึ้นไป ระบบจะถือว่าแอป เป็นแบบเปิดตลอดเวลา จอแสดงผลจะหรี่แสงลง แต่แอปพลิเคชันจะยังทำงานต่อไปและยังคงมองเห็นได้ (การอัปเดตอาจเกิดขึ้นนานๆ ครั้ง เช่น ทุกๆ 1 นาที) สถานะนี้แสดงด้วยโหนด "AOD ทั่วโลก" ในโฟลว์ชาร์ตต่อไปนี้

ปรับแต่งลักษณะการทำงานสำหรับสถานะแอมเบียนท์

ไม่ว่าลักษณะการทำงานของระบบเริ่มต้นจะเป็นอย่างไร คุณสามารถปรับแต่งลักษณะหรือลักษณะการทำงานของแอปขณะอยู่ในสถานะรอบข้างได้ใน Wear OS ทุกเวอร์ชันโดย ใช้ AmbientLifecycleObserver เพื่อฟังการเรียกกลับในการเปลี่ยนสถานะ สถานะนี้แสดงโดยโหนด "โหมด Ambiactive" ในโฟลว์ชาร์ตต่อไปนี้

ใช้ AmbientLifecycleObserver

หากต้องการตอบสนองต่อเหตุการณ์ในโหมดแอมเบียนท์ ให้ใช้คลาส AmbientLifecycleObserver

  1. ใช้AmbientLifecycleObserver.AmbientLifecycleCallback อินเทอร์เฟซ ใช้onEnterAmbient()เพื่อปรับ UI สำหรับ สถานะพลังงานต่ำ และonExitAmbient()เพื่อคืนค่าเป็นจอแสดงผลแบบอินเทอร์แอกทีฟเต็มรูปแบบ

    val ambientCallback = object : AmbientLifecycleObserver.AmbientLifecycleCallback {
        override fun onEnterAmbient(ambientDetails: AmbientLifecycleObserver.AmbientDetails) {
            // ... Called when moving from interactive mode into ambient mode.
            // Adjust UI for low-power state: dim colors, hide non-essential elements.
        }
    
        override fun onExitAmbient() {
            // ... Called when leaving ambient mode, back into interactive mode.
            // Restore full UI.
        }
    
        override fun onUpdateAmbient() {
            // ... Called by the system periodically (typically once per minute)
            // to allow the app to update its display while in ambient mode.
        }
    }

  2. สร้าง AmbientLifecycleObserver และลงทะเบียนด้วยวงจรของ กิจกรรมหรือ Composable

    private val ambientObserver = AmbientLifecycleObserver(activity, ambientCallback)
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycle.addObserver(ambientObserver)
    
        // ...
    }

  3. โทรหา removeObserver() เพื่อนำผู้สังเกตการณ์ออกใน onDestroy()

    override fun onDestroy() {
        super.onDestroy()
        lifecycle.removeObserver(ambientObserver)
    
        // ...
    }

สำหรับนักพัฒนาแอปที่ใช้ Jetpack Compose ไลบรารี Horologist มี ยูทิลิตีที่มีประโยชน์คือ Composable AmbientAware ซึ่งช่วยลดความซับซ้อนในการใช้งาน รูปแบบนี้

TimeText ที่รับรู้บรรยากาศโดยรอบ

ใน Wear OS 6 TimeText วิดเจ็ตจะรับรู้ถึงโหมดแอมเบียนท์ ซึ่งเป็นข้อยกเว้นที่ไม่ต้องใช้ Observer ที่กำหนดเอง โดยจะอัปเดตโดยอัตโนมัติทุกๆ 1 นาทีเมื่ออุปกรณ์อยู่ในสถานะแอมเบียนท์โดยไม่ต้องใช้โค้ดเพิ่มเติม

โฟลว์ชาร์ตลักษณะการทำงานของ Ambient

แผนผังลำดับงานต่อไปนี้แสดงวิธีที่ระบบกำหนดลักษณะการทำงานในโหมดแอมเบียนท์ โดยอิงตามเวอร์ชัน Wear OS ของอุปกรณ์ targetSdkVersion ของแอป และดูว่าแอปใช้ AmbientLifecycleCallback หรือไม่

โฟลว์ชาร์ตแสดงตรรกะการตัดสินใจสำหรับโหมดแอมเบียนท์ของ Wear OS โดยจะแสดงวิธีที่เวอร์ชันระบบปฏิบัติการของอุปกรณ์และการกำหนดค่าของแอปกำหนดผลลัพธ์ 1 ใน 3 อย่าง ได้แก่ ภาพซ้อนทับเบลอ, AOD ทั่วโลก หรือโหมด Ambiactive ที่แอปจัดการ
รูปที่ 1: โฟลว์ชาร์ตที่แสดงตรรกะการตัดสินใจสำหรับโหมดแอมเบียนท์ของ Wear OS

ควบคุมระยะเวลาการเปิดหน้าจอ

ส่วนต่อไปนี้อธิบายวิธีจัดการระยะเวลาที่แอปจะแสดงบนหน้าจอ

ป้องกันไม่ให้ระบบกลับไปที่หน้าปัดเมื่อมีกิจกรรมที่กำลังดำเนินอยู่

หลังจากอยู่ในสถานะรอบข้างเป็นระยะเวลาหนึ่ง (หมดเวลา #2) โดยปกติแล้วระบบจะ กลับไปที่หน้าปัด ผู้ใช้สามารถกำหนดค่าระยะหมดเวลาได้ ในการตั้งค่าระบบ ในบางกรณี เช่น ผู้ใช้ติดตามการออกกำลังกาย แอปอาจต้องแสดงไว้นานขึ้น

ใน Wear OS 5 ขึ้นไป คุณป้องกันปัญหานี้ได้โดยการใช้กิจกรรมที่กำลังดำเนินอยู่ หากแอปแสดงข้อมูลเกี่ยวกับงานของผู้ใช้ที่กำลังดำเนินการอยู่ เช่น เซสชันการออกกำลังกาย คุณสามารถใช้ Ongoing Activity API เพื่อให้ แอปของคุณยังคงมองเห็นได้จนกว่างานจะสิ้นสุด หากผู้ใช้กลับไปที่หน้าปัดด้วยตนเอง สัญญาณบอกสถานะกิจกรรมต่อเนื่องจะช่วยให้ผู้ใช้กลับไปที่แอปของคุณได้ด้วยการแตะเพียงครั้งเดียว

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

val activityIntent =
    Intent(this, AlwaysOnActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
    }

val pendingIntent =
    PendingIntent.getActivity(
        this,
        0,
        activityIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
    )

val notificationBuilder =
    NotificationCompat.Builder(this, CHANNEL_ID)
        // ...
        // ...
        .setOngoing(true)

// ...

val ongoingActivity =
    OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
        // ...
        // ...
        .setTouchIntent(pendingIntent)
        .build()

ongoingActivity.apply(applicationContext)

val notification = notificationBuilder.build()

เปิดหน้าจอไว้และป้องกันไม่ให้เข้าสู่สถานะแอมเบียนท์

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

คำแนะนำสำหรับโหมดแอมเบียนท์

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

  • ลดความเกะกะของภาพและเพิ่มประสิทธิภาพการแสดงผล UI ที่สะอาดและเรียบง่ายจะส่งสัญญาณ ให้ผู้ใช้ทราบว่าแอปอยู่ในสถานะใช้พลังงานต่ำและประหยัด แบตเตอรี่ได้อย่างมากด้วยการจำกัดพิกเซลสว่าง
    • ให้หน้าจอเป็นสีดำอย่างน้อย 85%
    • แสดงเฉพาะข้อมูลที่สำคัญที่สุด และย้ายรายละเอียดรองไปยัง จอแสดงผลแบบอินเทอร์แอกทีฟ
    • ใช้เส้นขอบสำหรับไอคอนหรือปุ่มขนาดใหญ่แทนการเติมสีทึบ
    • หลีกเลี่ยงการใช้บล็อกสีทึบขนาดใหญ่และแบรนด์หรือ ภาพพื้นหลังที่ไม่มีฟังก์ชัน
  • จัดการข้อมูลแบบไดนามิกที่ล้าสมัย
    • ระบบจะเรียกใช้onUpdateAmbient()การเรียกกลับเป็นระยะๆ เท่านั้น โดยปกติจะเรียกใช้ 1 ครั้งต่อนาทีเพื่อประหยัดพลังงาน เนื่องจากข้อจำกัดนี้ ข้อมูลที่มีการเปลี่ยนแปลงบ่อย เช่น นาฬิกาจับเวลา อัตราการเต้นของหัวใจ หรือระยะทางการออกกำลังกาย จะกลายเป็นข้อมูลที่ล้าสมัยระหว่างการอัปเดต หากต้องการหลีกเลี่ยงการแสดงข้อมูลที่ไม่ถูกต้องและทำให้เข้าใจผิด ให้รอ onEnterAmbientการเรียกกลับ แล้วแทนที่ค่าแบบเรียลไทม์เหล่านี้ด้วยเนื้อหาตัวยึดตำแหน่งแบบคงที่ เช่น --
  • คงเลย์เอาต์ให้สอดคล้องกัน
    • วางองค์ประกอบในตำแหน่งเดียวกันในโหมดอินเทอร์แอกทีฟและแอมเบียนท์ เพื่อสร้างการเปลี่ยนผ่านที่ราบรื่น
    • แสดงเวลาเสมอ
  • คำนึงถึงบริบท
    • หากผู้ใช้อยู่ในหน้าจอการตั้งค่าหรือการกำหนดค่าเมื่ออุปกรณ์ เข้าสู่โหมดแอมเบียนท์ ให้พิจารณาแสดงหน้าจอที่เกี่ยวข้องมากขึ้นจากแอป แทนมุมมองการตั้งค่า
  • จัดการข้อกำหนดเฉพาะของอุปกรณ์
    • ในออบเจ็กต์ AmbientDetails ที่ส่งไปยัง onEnterAmbient() ให้ทำดังนี้
      • หาก deviceHasLowBitAmbient เป็น true ให้ปิดใช้การลบรอยหยักหากเป็นไปได้
      • หาก burnInProtectionRequired เป็น true ให้เลื่อนองค์ประกอบ UI เล็กน้อยเป็นระยะๆ และหลีกเลี่ยงพื้นที่สีขาวทึบเพื่อป้องกันจอเบิร์น

การแก้ไขข้อบกพร่องและการทดสอบ

คำสั่ง adb เหล่านี้อาจมีประโยชน์เมื่อพัฒนาหรือทดสอบลักษณะการทำงานของแอป เมื่ออุปกรณ์อยู่ในโหมดแอมเบียนท์

# put device in ambient mode if the always on display is enabled in settings
# (and not disabled by other settings, such as theatre mode)
$ adb shell input keyevent KEYCODE_SLEEP

# put device in interactive mode
$ adb shell input keyevent KEYCODE_WAKEUP

ตัวอย่าง: แอปออกกำลังกาย

ลองพิจารณาแอปออกกำลังกายที่ต้องแสดงเมตริกต่อผู้ใช้ตลอด ระยะเวลาเซสชันการออกกำลังกาย แอปต้องยังคงมองเห็นได้ผ่านการเปลี่ยนสถานะแอมเบียนท์และไม่ถูกแทนที่ด้วยหน้าปัดนาฬิกา

หากต้องการดำเนินการดังกล่าว นักพัฒนาแอปควรทำดังนี้

  1. ใช้ AmbientLifecycleObserver เพื่อจัดการการเปลี่ยนแปลง UI ระหว่างสถานะโต้ตอบและแอมเบียนท์ เช่น การหรี่หน้าจอและนำข้อมูลที่ไม่จำเป็นออก
  2. สร้างเลย์เอาต์ใหม่ที่ใช้พลังงานต่ำสำหรับสถานะAmbient ที่เป็นไปตาม แนวทางปฏิบัติแนะนำ
  3. ใช้ Ongoing Activity API ตลอดระยะเวลาการออกกำลังกายเพื่อป้องกันไม่ให้ระบบกลับไปที่หน้าปัด

ดูการใช้งานที่สมบูรณ์ได้ในตัวอย่างการออกกำลังกายที่อิงตาม Compose ใน GitHub ตัวอย่างนี้ยังแสดงการใช้ AmbientAware ที่ประกอบได้จากไลบรารี Horologist เพื่อลดความซับซ้อนในการจัดการโหมดแอมเบียนท์ ใน Compose