Ứng dụng luôn bật và chế độ môi trường xung quanh của hệ thống

Hướng dẫn này giải thích cách làm cho ứng dụng của bạn luôn bật, cách phản ứng với các quá trình chuyển đổi trạng thái nguồn và cách quản lý hành vi của ứng dụng để mang lại trải nghiệm tốt cho người dùng trong khi tiết kiệm pin.

Việc cho phép một ứng dụng liên tục xuất hiện sẽ ảnh hưởng đáng kể đến thời lượng pin, vì vậy bạn hãy cân nhắc mức tiêu thụ điện năng khi thêm tính năng này.

Khái niệm chính

Khi một ứng dụng Wear OS xuất hiện ở chế độ toàn màn hình, ứng dụng đó sẽ ở một trong hai trạng thái nguồn sau:

  • Tương tác: Trạng thái tiêu thụ nhiều năng lượng, trong đó màn hình có độ sáng tối đa, cho phép người dùng tương tác đầy đủ.
  • Môi trường xung quanh: Trạng thái tiêu thụ ít điện năng, trong đó màn hình giảm độ sáng để tiết kiệm pin. Ở trạng thái này, giao diện người dùng của ứng dụng vẫn chiếm toàn bộ màn hình, nhưng hệ thống có thể thay đổi giao diện bằng cách làm mờ hoặc hiển thị nội dung lớp phủ như thời gian. Đây còn được gọi là Chế độ môi trường xung quanh.

Hệ điều hành kiểm soát quá trình chuyển đổi giữa các trạng thái này.

Ứng dụng luôn bật là ứng dụng hiển thị nội dung ở cả trạng thái Tương tác và Môi trường xung quanh.

Khi một ứng dụng luôn bật tiếp tục hiển thị giao diện người dùng của riêng ứng dụng trong khi thiết bị ở trạng thái Môi trường xung quanh có mức sử dụng điện năng thấp, thì ứng dụng đó được mô tả là đang ở chế độ ambiactive.

Quá trình chuyển đổi hệ thống và hành vi mặc định

Khi một ứng dụng chạy ở nền trước, hệ thống sẽ quản lý các quá trình chuyển đổi trạng thái nguồn dựa trên 2 khoảng thời gian chờ do người dùng không hoạt động kích hoạt.

  • Timeout #1: Trạng thái Tương tác sang trạng thái Môi trường xung quanh: Sau một khoảng thời gian người dùng không hoạt động, thiết bị sẽ chuyển sang trạng thái Môi trường xung quanh.
  • Thời gian chờ #2: Trở về mặt đồng hồ: Sau một khoảng thời gian không hoạt động nữa, hệ thống có thể ẩn ứng dụng hiện tại và hiển thị mặt đồng hồ.

Ngay sau khi hệ thống chuyển đổi lần đầu tiên sang trạng thái Môi trường xung quanh, hành vi mặc định sẽ phụ thuộc vào phiên bản Wear OS và cấu hình của ứng dụng:

  • Trên Wear OS 5 trở xuống, hệ thống sẽ hiển thị ảnh chụp màn hình bị mờ của ứng dụng đang tạm dừng, với thời gian được phủ lên trên. Trạng thái này được biểu thị bằng nút "AOD Lite" trong sơ đồ quy trình sau.
  • Trên Wear OS 6 trở lên, nếu một ứng dụng nhắm đến SDK 36 trở lên, thì ứng dụng đó được coi là luôn bật. Màn hình sẽ mờ đi nhưng ứng dụng vẫn tiếp tục chạy và hiển thị. (Các bản cập nhật có thể diễn ra không thường xuyên, chẳng hạn như chỉ một lần mỗi phút.) Trạng thái này được biểu thị bằng nút "Global AOD" trong sơ đồ quy trình sau.

Tuỳ chỉnh hành vi cho trạng thái Môi trường xung quanh

Bất kể hành vi mặc định của hệ thống, trên tất cả các phiên bản Wear OS, bạn đều có thể tuỳ chỉnh giao diện hoặc hành vi của ứng dụng khi ở trạng thái Môi trường xung quanh bằng cách sử dụng LocalAmbientModeManager để theo dõi các quá trình chuyển đổi trạng thái trong Jetpack Compose trên Wear OS. Trạng thái này được biểu thị bằng nút "Chế độ Ambiactive" trong sơ đồ quy trình sau.

Quan sát trạng thái môi trường xung quanh

Cách phản ứng với các sự kiện ở chế độ xung quanh trong Jetpack Compose trên Wear OS:

  1. Sử dụng LocalAmbientModeManager để theo dõi các thay đổi đối với trạng thái chế độ xung quanh của hệ thống, điều chỉnh các thành phần kết hợp cho phù hợp. Định cấu hình thành phần để điều chỉnh sang chế độ công suất thấp ở trạng thái AmbientMode.Ambient và khôi phục thành chế độ hiển thị tương tác đầy đủ ở trạng thái AmbientMode.Interactive.

    // In a production application, the AmbientModeManager should be instantiated and provided at
    // the highest level of the Compose hierarchy (typically in the host Activity's setContent
    // block) using a CompositionLocalProvider. This ensures proper lifecycle management and
    // broad accessibility.
    
    // For this self-contained demo, AmbientModeManager is created and provided locally:
    val activityAmbientModeManager = rememberAmbientModeManager()
    CompositionLocalProvider(LocalAmbientModeManager provides activityAmbientModeManager) {
        val ambientModeManager = LocalAmbientModeManager.current
        val ambientMode = ambientModeManager?.currentAmbientMode
    
        if (ambientModeManager != null) {
            ambientModeManager.AmbientTickEffect {
                // While device is in ambient mode, update properties every minute or so
                // ...
            }
        }
    
        // ...
            val ambientModeName =
                when (ambientMode) {
                    is AmbientMode.Interactive -> "Interactive"
                    is AmbientMode.Ambient -> "Ambient"
                    else -> "Unknown"
                }
    
            Text(text = "$ambientModeName Mode")
            // ...
    }

Lưu đồ hành vi ở chế độ xung quanh

Sơ đồ quy trình sau đây minh hoạ cách hệ thống xác định hành vi ở chế độ xung quanh dựa trên phiên bản Wear OS của thiết bị, targetSdkVersion của ứng dụng và việc ứng dụng có quan sát các quá trình chuyển đổi trạng thái xung quanh hay không (bằng cách sử dụng LocalAmbientModeManager hoặc AmbientLifecycleCallback).

Sơ đồ quy trình minh hoạ logic quyết định cho chế độ môi trường xung quanh của Wear OS. Ví dụ này cho thấy phiên bản hệ điều hành của thiết bị và cấu hình của ứng dụng xác định một trong 3 kết quả: lớp phủ bị mờ, AOD toàn cầu hoặc Chế độ Ambiactive do ứng dụng quản lý.
Hình 1.: Sơ đồ quy trình minh hoạ logic quyết định cho chế độ môi trường xung quanh của Wear OS.

Kiểm soát thời lượng bật màn hình

Các phần sau đây mô tả cách quản lý thời gian ứng dụng của bạn xuất hiện trên màn hình.

Ngăn người dùng quay lại mặt đồng hồ bằng một Hoạt động đang diễn ra hoặc Thông tin cập nhật trực tiếp

Sau một khoảng thời gian ở trạng thái Môi trường xung quanh (Hết thời gian chờ 2), hệ thống thường sẽ quay lại mặt đồng hồ. Người dùng có thể định cấu hình khoảng thời gian chờ trong phần cài đặt hệ thống. Đối với một số trường hợp sử dụng, chẳng hạn như khi người dùng theo dõi một bài tập thể dục, ứng dụng có thể cần duy trì trạng thái hiển thị lâu hơn.

Trên Wear OS 5 trở lên, bạn có thể ngăn chặn điều này bằng cách triển khai một OngoingActivity (Hoạt động đang diễn ra). Nếu ứng dụng của bạn đang hiển thị thông tin về một tác vụ đang diễn ra của người dùng (chẳng hạn như một phiên tập thể dục), thì bạn có thể dùng Ongoing Activity API để giữ cho ứng dụng của bạn hiển thị cho đến khi tác vụ kết thúc. Nếu người dùng tự quay lại mặt đồng hồ, chỉ báo hoạt động đang diễn ra sẽ cung cấp một cách thức để họ quay lại ứng dụng của bạn chỉ bằng một lần nhấn.

Ngoài ra, trên Wear OS 7 trở lên, bạn có thể sử dụng Thông tin cập nhật trực tiếp thay cho Hoạt động đang diễn ra. Để có khả năng tương thích ngược, hãy tiếp tục hỗ trợ Hoạt động đang diễn ra trên các thiết bị chạy Wear OS 6 trở xuống.

Để triển khai việc này, ý định chạm của thông báo hiển thị liên tục phải trỏ đến hoạt động luôn bật của bạn, như minh hoạ trong đoạn mã sau:

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

Luôn bật màn hình và ngăn Chế độ hiển thị thông minh

Trong một số ít trường hợp, bạn có thể cần ngăn hoàn toàn thiết bị chuyển sang trạng thái Môi trường xung quanh. Tức là để tránh bị hết thời gian chờ lần 1. Để làm việc này, bạn có thể sử dụng đối tượng sửa đổi keepScreenOn. Hàm này hoạt động như một khoá chế độ thức, giữ thiết bị ở trạng thái Interactive. Hãy sử dụng tính năng này một cách hết sức thận trọng vì tính năng này ảnh hưởng nghiêm trọng đến thời lượng pin.

Đề xuất cho Chế độ môi trường xung quanh

Để mang lại trải nghiệm tốt nhất cho người dùng và tiết kiệm pin ở chế độ Môi trường xung quanh, hãy làm theo các nguyên tắc thiết kế này. Những đề xuất này ưu tiên trải nghiệm rõ ràng cho người dùng bằng cách ngăn chặn thông tin gây hiểu lầm và giảm bớt sự lộn xộn về hình ảnh, đồng thời tối ưu hoá sức mạnh hiển thị.

  • Giảm tình trạng rối mắt và mức tiêu thụ điện của màn hình. Giao diện người dùng tối giản, gọn gàng cho người dùng biết rằng ứng dụng đang ở trạng thái tiêu thụ ít năng lượng và tiết kiệm đáng kể pin bằng cách giới hạn các pixel sáng.
    • Giữ ít nhất 85% màn hình có màu đen (tỷ lệ điểm ảnh bật là 15% hoặc ít hơn).
    • Chỉ hiển thị thông tin quan trọng nhất, chuyển các thông tin chi tiết thứ cấp sang màn hình tương tác.
    • Sử dụng đường viền cho các biểu tượng hoặc nút lớn thay vì tô màu đồng nhất, điều chỉnh độ tương phản của đường viền để các phần tử vẫn dễ đọc mà không có nguy cơ màn hình nhấp nháy hoặc bị lưu ảnh.
    • Tránh sử dụng các khối màu đồng nhất lớn và hình ảnh thương hiệu hoặc hình nền không hoạt động.
  • Xử lý dữ liệu và ảnh động động đã lỗi thời
    • Lệnh gọi lại AmbientTickEffect chỉ được gọi định kỳ (thường là một lần mỗi phút) để tiết kiệm pin. Do hạn chế này, mọi dữ liệu thay đổi thường xuyên (chẳng hạn như đồng hồ bấm giờ, tần số tim hoặc khoảng cách tập luyện) sẽ trở nên cũ giữa các lần cập nhật. Để tránh hiển thị thông tin sai lệch và không chính xác, hãy thay thế các giá trị động này bằng nội dung tĩnh của phần giữ chỗ, chẳng hạn như --.
    • Xoá những chỉ báo tiến trình cần được cập nhật thường xuyên để hữu ích cho bối cảnh hoặc tình huống hiện tại của người dùng, chẳng hạn như vòng tiến trình cho các phiên nội dung nghe nhìn ngắn. Bạn có thể giữ lại các chỉ báo tiến trình khi các bản cập nhật mỗi phút một lần vẫn mang lại giá trị, chẳng hạn như đối với đồng hồ hẹn giờ dài.
    • Tạm dừng hoặc xoá tất cả ảnh động ở chế độ xung quanh, bao gồm cả chỉ báo tiến trình có ảnh động và văn bản chạy.
  • Duy trì bố cục nhất quán
    • Giữ các phần tử ở cùng một vị trí trong chế độ Tương tác và Môi trường xung quanh để tạo hiệu ứng chuyển đổi mượt mà. Các phần tử tương tác trên giao diện người dùng (chẳng hạn như nút) vẫn có thể hiển thị vì các thiết bị Wear OS hiện đại hỗ trợ thao tác chạm trong các phiên ở chế độ môi trường xung quanh.
    • Luôn hiển thị giờ hiện tại. Trong Jetpack Compose cho Wear OS, TimeText (theo mặc định có trong ScreenScaffold) nhận biết môi trường xung quanh và tự động cập nhật mỗi phút một lần ở chế độ môi trường xung quanh.
  • Nắm bắt bối cảnh
    • Nếu người dùng đang ở trên màn hình cài đặt hoặc cấu hình khi thiết bị chuyển sang chế độ môi trường xung quanh, hãy cân nhắc việc hiển thị một màn hình phù hợp hơn trong ứng dụng của bạn thay vì chế độ xem cài đặt.
  • Xử lý các yêu cầu cụ thể theo thiết bị
    • Khi currentAmbientMode trả về AmbientMode.Ambient:
      • Nếu isLowBitAmbientSupported là true, thì màn hình sẽ hỗ trợ ít bit hơn cho mỗi màu ở chế độ môi trường xung quanh. Tắt tính năng khử răng cưa (ví dụ: trong các thao tác vẽ Canvas hoặc Paint tuỳ chỉnh) và tránh chuyển màu nếu có thể.
      • Nếu isBurnInProtectionRequired là true, hệ thống sẽ định kỳ chuyển nội dung hiển thị để ngăn hiện tượng cháy màn hình. Đừng tự di chuyển các phần tử trên giao diện người dùng trong ứng dụng. Thay vào đó, hãy tránh các vùng màu trắng và đặt các phần tử quan trọng trên giao diện người dùng cách cạnh màn hình ít nhất 10 pixel để chúng không bị cắt khi hệ thống di chuyển màn hình. (Các bố cục Wear Compose tiêu chuẩn, chẳng hạn như ScreenScaffold, đã cung cấp đủ khoảng đệm ở cạnh.)

Gỡ lỗi và thử nghiệm

Các lệnh adb này có thể hữu ích khi bạn phát triển hoặc kiểm thử cách ứng dụng hoạt động khi thiết bị ở chế độ xung quanh:

# 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

Ví dụ: Ứng dụng tập luyện

Hãy cân nhắc một ứng dụng tập thể dục cần hiển thị các chỉ số cho người dùng trong toàn bộ thời gian của phiên tập thể dục. Ứng dụng phải luôn hiển thị trong quá trình chuyển đổi trạng thái Môi trường xung quanh và tránh bị mặt đồng hồ thay thế.

Để đạt được điều này, nhà phát triển cần làm như sau:

  1. Sử dụng LocalAmbientModeManager để xử lý các thay đổi về giao diện người dùng giữa các trạng thái Tương tác và Môi trường xung quanh, chẳng hạn như làm mờ màn hình và xoá dữ liệu không cần thiết.
  2. Tạo một bố cục mới có mức sử dụng điện năng thấp cho trạng thái Môi trường xung quanh theo các phương pháp hay nhất.
  3. Sử dụng Ongoing Activity API (hoặc Thông tin cập nhật trực tiếp trên Wear OS 7 trở lên) trong suốt thời gian tập luyện để ngăn hệ thống quay lại mặt đồng hồ.

Để xem cách triển khai đầy đủ, hãy xem Mẫu bài tập thể dục dựa trên Compose trên GitHub. Mẫu này cũng minh hoạ cách sử dụng thành phần kết hợp LocalAmbientModeManager để đơn giản hoá việc xử lý chế độ môi trường xung quanh trong Compose.