Tiện ích WindowManager

Thư viện Jetpack WindowManager cho phép nhà phát triển ứng dụng hỗ trợ các kiểu dáng thiết bị mới và môi trường nhiều cửa sổ.

WindowManager Extensions (Extensions) là một mô-đun nền tảng Android không bắt buộc, cho phép nhiều tính năng của Jetpack WindowManager. Mô-đun này được triển khai trong AOSP trong frameworks/base/libs/WindowManager/Jetpack và được cung cấp trên các thiết bị hỗ trợ các tính năng của WindowManager.

Phân phối mô-đun tiện ích

Các tiện ích được biên dịch thành thư viện .jar và được đặt trong phân vùng system_ext trên thiết bị nếu Tiện ích được bật trong tệp makefile của thiết bị.

Để bật Tiện ích trên thiết bị, hãy thêm nội dung sau vào tệp makefile của thiết bị sản phẩm:

$(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk)

Thao tác này sẽ bật các gói androidx.window.extensionsandroidx.window.sidecar trên thiết bị, đồng thời đặt thuộc tính persist.wm.extensions.enabled. Việc đưa các gói này vào makefile cũng sẽ đặt các khai báo trong etc/permissions/, giúp các quy trình ứng dụng có thể sử dụng các gói này. Thông thường, các mô-đun sẽ được tải vào và thực thi như một phần của quy trình ứng dụng tại thời gian chạy khi được thư viện Jetpack WindowManager sử dụng. Điều này khiến hoạt động của mô-đun tương tự như mã khung phía máy khách, như minh hoạ trong hình sau:

Hình 1. Tiện ích WindowManager được tải vào quy trình ứng dụng tương tự như mã nền tảng.

Mô-đun androidx.window.extensions là mô-đun Tiện ích hiện tại đang trong quá trình phát triển. Mô-đun androidx.window.sidecar là một mô-đun cũ được đưa vào để tương thích với các phiên bản đầu tiên của Jetpack WindowManager, nhưng không còn được duy trì nữa.

Hình sau đây cho thấy logic để xác định việc sử dụng androidx.window.extensions hoặc androidx.window.sidecar.

Hình 2. Cây quyết định để truy cập vào androidx.window.extensions hoặc androidx.window.sidecar.

Mô-đun tiện ích

Các tiện ích cung cấp các tính năng tạo cửa sổ cho thiết bị có màn hình lớn có thể gập lại và các thiết bị hỗ trợ tính năng tạo cửa sổ trên màn hình ngoài. Các khu vực có tính năng này bao gồm:

Các hoạt động triển khai Tiện ích của OEM có thể cung cấp các thành phần rỗng hoặc các thành phần có hoạt động triển khai mặc định hoặc hoạt động triển khai stub của các phương thức trong giao diện WindowExtensions nếu phần cứng thiết bị không hỗ trợ các tính năng tương ứng, trừ phi tính năng đó được yêu cầu cụ thể trong Tài liệu định nghĩa về khả năng tương thích (CDD) 7.1.1.1.

Tiện ích và API Jetpack

Ngoài các API nền tảng công khai, mô-đun Tiện ích WindowManager còn cung cấp giao diện API riêng. Mô-đun Tiện ích được phát triển công khai trong một thư viện Jetpack androidx.window.extensions không dành cho nhà phát triển, để Jetpack WindowManager (androidx.window) có thể liên kết với mô-đun này tại thời điểm biên dịch. Nền tảng Extensions API thường cung cấp các API cấp thấp hơn.

Các API mà Tiện ích cung cấp chỉ dành cho thư viện Jetpack WindowManager. Các nhà phát triển ứng dụng không nên trực tiếp gọi Extensions API. Bạn không được thêm thư viện Tiện ích làm phần phụ thuộc cho một ứng dụng trong tệp bản dựng Gradle để đảm bảo chức năng hoạt động chính xác. Tránh biên dịch trước thư viện Tiện ích trực tiếp vào một ứng dụng; thay vào đó, hãy dựa vào quá trình tải thời gian chạy để ngăn trường hợp tải hỗn hợp các lớp Tiện ích được cung cấp trong thời gian chạy và được biên dịch trước.

Jetpack WindowManager (androidx.window) được thêm dưới dạng một phần phụ thuộc của ứng dụng và cung cấp các API công khai dành cho nhà phát triển, bao gồm cả các API cho các tính năng của Tiện ích WindowManager. Thư viện WindowManager tự động tải Tiện ích vào quy trình ứng dụng và bao bọc các API Tiện ích cấp thấp hơn thành các trừu tượng cấp cao hơn và các giao diện tập trung hơn. Các API WindowManager Jetpack tuân theo các tiêu chuẩn phát triển ứng dụng Android hiện đại và nhằm mục đích cung cấp khả năng tương tác thuận tiện bằng cách tích hợp tốt với các cơ sở mã sử dụng các thư viện AndroidX khác.

Phiên bản và bản cập nhật của tiện ích

Bạn có thể cập nhật mô-đun Tiện ích cùng với các bản cập nhật hằng năm hoặc hằng quý của nền tảng Android. Các bản cập nhật hằng quý cho phép tăng cấp độ API Tiện ích giữa các bản cập nhật API nền tảng Android, giúp quá trình lặp lại diễn ra nhanh hơn và mang đến cho các OEM cơ hội thêm quyền truy cập API chính thức vào các tính năng mới gần với thời điểm ra mắt phần cứng.

Bảng sau đây liệt kê các phiên bản API androidx.window.extensions cho nhiều bản phát hành Android.

Phiên bản của Nền tảng Android Cấp độ API của Tiện ích WindowManager Phiên bản API androidx.window.extensions
Android 15 6 1.5.0 (sắp ra mắt)
Android 14 QPR3 5 1.4.0 (sắp ra mắt)
Android 14 QPR1 4 1.3.0
Android 14 3 1.2.0
Android 13 QPR3 2 1.1.0
Android 13 1 1.0.0
Android 12L 1 1.0.0

Cấp độ Extensions API (cột ở giữa) sẽ tăng lên mỗi khi có một thành phần mới được thêm vào giao diện API ổn định hiện có (cột bên phải).

Khả năng tương thích ngược và tương thích chuyển tiếp

Jetpack WindowManager xử lý sự phức tạp khi đối phó với các bản cập nhật cấp API thường xuyên, sự phát triển nhanh chóng của API và khả năng tương thích ngược. Khi mã thư viện được thực thi trong quy trình ứng dụng, thư viện sẽ kiểm tra cấp độ API Extensions đã khai báo và cung cấp quyền truy cập vào các tính năng theo cấp độ đã khai báo.

Để bảo vệ ứng dụng khỏi bị lỗi trong thời gian chạy, WindowManager cũng thực hiện một quy trình kiểm tra phản chiếu Java trong thời gian chạy đối với các API Tiện ích hiện có theo cấp độ API Tiện ích đã khai báo. Nếu có sự không khớp, WindowManager có thể tắt việc sử dụng Tiện ích (một phần hoặc toàn bộ) và báo cáo các tính năng liên quan là không có sẵn cho ứng dụng.

Tiện ích WindowManager được triển khai dưới dạng một mô-đun system_ext sử dụng các API nền tảng riêng tư để gọi vào lõi WindowManager, DeviceStateManager và các dịch vụ hệ thống khác trong quá trình triển khai các tính năng của Tiện ích.

Khả năng tương thích có thể không được duy trì với các phiên bản Tiện ích trước khi phát hành trước khi có bản phát hành nền tảng Android tương ứng theo quý hoặc theo năm mà các phiên bản được hoàn thiện. Bạn có thể xem toàn bộ nhật ký của API Extensions trong tệp văn bản API window:extensions:extensions của nhánh phát hành.

Các phiên bản mới hơn của Extensions phải tiếp tục hoạt động với các phiên bản cũ hơn của WindowManager được biên dịch thành các ứng dụng để duy trì khả năng tương thích về sau. Để đảm bảo điều này, mọi phiên bản mới của Extensions API chỉ thêm các API mới và không xoá các API cũ. Do đó, các ứng dụng có phiên bản WindowManager cũ hơn có thể tiếp tục sử dụng các Extensions API cũ mà ứng dụng được biên dịch.

Quy trình xác minh CTS đảm bảo rằng đối với mọi phiên bản đã khai báo của API Tiện ích trên thiết bị, tất cả API cho phiên bản đó và các phiên bản trước đều có mặt và hoạt động.

Hiệu suất

Theo mặc định, mô-đun Tiện ích được lưu vào bộ nhớ đệm trong trình tải lớp hệ thống không phải bootclasspath kể từ Android 14 (API cấp 34), nên không có tác động nào đến hiệu suất do tải mô-đun vào bộ nhớ khi khởi động ứng dụng. Việc sử dụng các tính năng của từng mô-đun có thể ảnh hưởng một chút đến đặc điểm hiệu suất của ứng dụng khi các lệnh gọi IPC bổ sung được thực hiện giữa máy khách và máy chủ.

Mô-đun

Nhúng hoạt động

Thành phần nhúng hoạt động cho phép các ứng dụng tối ưu hoá giao diện người dùng cho các thiết bị màn hình lớn và màn hình ngoài. Tính năng nhúng hoạt động cho phép trình bày hai hoạt động cạnh nhau trong bố cục nhiều ngăn, tạo điều kiện thuận lợi cho việc phát triển ứng dụng thích ứng cho các ứng dụng cũ.

Thành phần nhúng hoạt động phải có trên tất cả các thiết bị có màn hình tích hợp từ sw600dp trở lên. Bạn cũng phải bật tính năng nhúng hoạt động trên các thiết bị hỗ trợ kết nối màn hình ngoài, vì ứng dụng có thể xuất hiện ở kích thước lớn hơn khi màn hình ngoài được kết nối trong thời gian chạy.

Cấu hình thiết bị

Bạn không cần phải thiết lập cấu hình thiết bị cụ thể nào khác ngoài việc bật mô-đun Tiện ích như mô tả trong phần Phân phối mô-đun Tiện ích. Bạn nên bật Tiện ích trên tất cả các thiết bị hỗ trợ chế độ nhiều cửa sổ. Các phiên bản Android trong tương lai có thể sẽ yêu cầu Tiện ích trên các cấu hình thiết bị cầm tay và màn hình lớn thông thường.

Thông tin về bố cục cửa sổ

Thành phần thông tin bố cục cửa sổ xác định vị trí và trạng thái của bản lề trên thiết bị có thể gập lại khi bản lề cắt ngang cửa sổ ứng dụng. Thông tin bố cục cửa sổ cho phép các ứng dụng phản hồi và hiển thị bố cục được tối ưu hoá ở chế độ trên mặt bàn trên thiết bị có thể gập lại. Hãy xem bài viết Giúp ứng dụng nhận biết chế độ gập để biết thông tin chi tiết về cách sử dụng.

Các thiết bị Android có thể gập lại có bản lề kết nối các khu vực bảng hiển thị riêng biệt hoặc liên tục phải cung cấp thông tin về bản lề cho các ứng dụng thông qua WindowLayoutComponent.

Bạn phải báo cáo vị trí và ranh giới của bản lề so với cửa sổ ứng dụng được xác định bằng Context được truyền vào API. Nếu ranh giới cửa sổ ứng dụng không giao với ranh giới bản lề, thì bạn không được báo cáo DisplayFeature bản lề. Bạn cũng có thể không báo cáo các tính năng hiển thị khi vị trí của chúng có thể không được báo cáo một cách đáng tin cậy, chẳng hạn như khi người dùng có thể di chuyển cửa sổ ứng dụng một cách tự do ở chế độ nhiều cửa sổ hoặc chế độ tương thích có khung viền hòm thư.

Đối với các tính năng có thể gập lại, bạn phải báo cáo các bản cập nhật trạng thái khi vị trí bản lề thay đổi giữa các trạng thái ổn định. Theo mặc định ở trạng thái màn hình phẳng, API phải báo cáo FoldingFeature.State.FLAT. Nếu phần cứng của thiết bị có thể ở trạng thái gập một nửa một cách ổn định, thì API phải báo cáo FoldingFeature.State.HALF_OPENED. Không có trạng thái đóng trong API, vì trong trường hợp như vậy, cửa sổ ứng dụng sẽ không hiển thị hoặc không vượt quá ranh giới bản lề.

Cấu hình thiết bị

Để hỗ trợ việc triển khai tính năng gập, các OEM phải làm như sau:

  • Định cấu hình các trạng thái thiết bị trong device_state_configuration.xml để DeviceStateManagerService sử dụng. Hãy xem DeviceStateProviderImpl.java để tham khảo.

    Nếu các phương thức triển khai mặc định của DeviceStateProvider hoặc DeviceStatePolicy không phù hợp với thiết bị, thì bạn có thể sử dụng một phương thức triển khai tuỳ chỉnh.

  • Bật mô-đun Tiện ích như mô tả trong phần Phân phối mô-đun Tiện ích.

  • Chỉ định vị trí của các tính năng hiển thị trong tài nguyên chuỗi com.android.internal.R.string.config_display_features (thường nằm trong frameworks/base/core/res/res/values/config.xml trong lớp phủ thiết bị).

    Định dạng cần thiết của chuỗi như sau:

    <type>-[<left>,<top>,<right>,<bottom>]

    type có thể là fold hoặc hinge. Giá trị của left, top, rightbottom là toạ độ pixel nguyên trong không gian toạ độ hiển thị theo hướng hiển thị tự nhiên. Chuỗi cấu hình có thể chứa nhiều tính năng hiển thị, phân tách bằng dấu chấm phẩy.

    Ví dụ:

    <!-- Jetpack WindowManager display features -->
    <string name="config_display_features" translatable="false">fold-[1000,0,1000,2000]</string>
    
  • Xác định mối liên kết giữa các giá trị nhận dạng trạng thái thiết bị nội bộ được dùng trong DeviceStateManager và các hằng số trạng thái công khai được gửi cho nhà phát triển trong com.android.internal.R.array.config_device_state_postures.

    Định dạng dự kiến cho mỗi mục là:

    <device_specific_state_identifier>:<Jetpack WindowManager state identifier>

    Sau đây là các giá trị nhận dạng tiểu bang được hỗ trợ:

    • COMMON_STATE_NO_FOLDING_FEATURES = 1: Trạng thái không có các tính năng gập để báo cáo. Ví dụ: đó có thể là trạng thái đóng của thiết bị gập vào trong thông thường với màn hình chính ở mặt trong.
    • COMMON_STATE_HALF_OPENED = 2: Tính năng gập đang mở một nửa.
    • COMMON_STATE_FLAT = 3: Tính năng gập có dạng phẳng. Ví dụ: đó có thể là trạng thái mở của thiết bị gập vào trong thông thường với màn hình chính ở mặt trong.
    • COMMON_STATE_USE_BASE_STATE = 1000: Trong Android 14, một giá trị có thể dùng cho các trạng thái được mô phỏng, trong đó trạng thái bản lề được lấy từ trạng thái cơ sở, như được xác định trong CommonFoldingFeature.java

    Hãy xem DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int) để biết thêm thông tin.

    Ví dụ:

    <!-- Map of System DeviceState supplied by DeviceStateManager to WindowManager posture.-->
    <string-array name="config_device_state_postures" translatable="false">
      <item>0:1</item>    <!-- CLOSED       : COMMON_STATE_NO_FOLDING_FEATURES -->
      <item>1:2</item>    <!-- HALF_OPENED  : COMMON_STATE_HALF_OPENED -->
      <item>2:3</item>    <!-- OPENED       : COMMON_STATE_FLAT -->
      <item>3:1</item>    <!-- REAR_DISPLAY : COMMON_STATE_NO_FOLDING_FEATURES -->
      <item>4:1000</item> <!-- CONCURRENT   : COMMON_STATE_USE_BASE_STATE -->
    </string-array>
    

Diện tích cửa sổ

Thành phần vùng cửa sổ cung cấp một tập hợp các tính năng giúp ứng dụng truy cập vào các màn hình và vùng hiển thị bổ sung trên một số thiết bị có thể gập lại và thiết bị có nhiều màn hình.

Chế độ màn hình sau cho phép một ứng dụng hiển thị giao diện người dùng xem trước của camera trên màn hình ngoài của thiết bị có thể gập lại để cho phép sử dụng camera chính của thiết bị cho ảnh chân dung tự chụp và video. Những thiết bị có màn hình ngoài tương thích với Android (theo định nghĩa của CDD Android về các thuộc tính như kích thước, mật độ và các chế độ thao tác điều hướng hiện có) phù hợp với camera sau của thiết bị phải cung cấp quyền truy cập vào chế độ màn hình sau.

Trên Android 14, chế độ Dual Screen cho phép các ứng dụng chạy trên màn hình trong của thiết bị có thể gập lại hiển thị nội dung bổ sung trên màn hình ngoài cho những người dùng khác; ví dụ: màn hình ngoài có thể hiển thị bản xem trước của camera cho người đang được chụp ảnh hoặc quay video.

Cấu hình thiết bị

Để hỗ trợ việc triển khai tính năng gập, các OEM phải làm như sau:

  • Định cấu hình các trạng thái thiết bị trong device_state_configuration.xml để DeviceStateManagerService sử dụng. Hãy xem DeviceStateProviderImpl.java để biết thêm thông tin.

    Nếu chế độ triển khai mặc định của DeviceStateProvider hoặc DeviceStatePolicy không phù hợp với thiết bị, thì bạn có thể sử dụng chế độ triển khai tuỳ chỉnh.

  • Đối với các thiết bị có thể gập lại hỗ trợ chế độ mở hoặc chế độ phẳng, hãy chỉ định các giá trị nhận dạng trạng thái tương ứng trong com.android.internal.R.array.config_openDeviceStates.

  • Đối với các thiết bị gập vào trong có hỗ trợ trạng thái gập, hãy liệt kê các mã nhận dạng trạng thái tương ứng trong com.android.internal.R.array.config_foldedDeviceStates.

  • Đối với các thiết bị gập vào trong có hỗ trợ trạng thái gập một nửa (bản lề mở một nửa như máy tính xách tay), hãy liệt kê các trạng thái tương ứng trong com.android.internal.R.array.config_halfFoldedDeviceStates.

  • Đối với các thiết bị hỗ trợ chế độ màn hình sau:

    • Liệt kê các trạng thái tương ứng trong com.android.internal.R.array.config_rearDisplayDeviceStates cho DeviceStateManager.
    • Chỉ định địa chỉ hiển thị thực tế của màn hình sau trong com.android.internal.R.string.config_rearDisplayPhysicalAddress.
    • Chỉ định giá trị nhận dạng trạng thái trong com.android.internal.R.integer.config_deviceStateRearDisplay để Tiện ích sử dụng.
    • Thêm mã nhận dạng trạng thái vào com.android.internal.R.array.config_deviceStatesAvailableForAppRequests để cung cấp cho các ứng dụng.
  • Trên Android 14, đối với những thiết bị hỗ trợ chế độ hiển thị kép (đồng thời):

    • Đặt com.android.internal.R.bool.config_supportsConcurrentInternalDisplays thành true.
    • Chỉ định địa chỉ hiển thị thực tế của màn hình sau trong com.android.internal.R.config_deviceStateConcurrentRearDisplay.
    • Chỉ định giá trị nhận dạng trạng thái trong com.android.internal.R.integer.config_deviceStateConcurrentRearDisplay mà Tiện ích sẽ dùng nếu giá trị nhận dạng đó được cung cấp cho các ứng dụng.
    • Thêm mã nhận dạng trạng thái vào com.android.internal.R.array.config_deviceStatesAvailableForAppRequests để cung cấp cho các ứng dụng.

Xác minh

Các OEM phải xác minh việc triển khai của mình để đảm bảo hành vi như mong đợi trong các trường hợp phổ biến. Các bài kiểm thử CTS và bài kiểm thử bằng Jetpack WindowManager được cung cấp cho các OEM để kiểm thử việc triển khai.

Các bài kiểm thử CTS

Để chạy các bài kiểm thử CTS, hãy xem phần Chạy các bài kiểm thử CTS. Các kiểm thử CTS liên quan đến Jetpack WindowManager nằm trong cts/tests/framework/base/windowmanager/jetpack/. Tên mô-đun kiểm thử là CtsWindowManagerJetpackTestCases.

Kiểm thử WindowManager

Để tải các kiểm thử Jetpack WindowManager xuống, hãy làm theo Hướng dẫn về Android Jetpack. Các kiểm thử nằm trong thư viện cửa sổ trong mô-đun window:window: window/window/src/androidTest/.

Để chạy kiểm thử thiết bị cho mô-đun window:window qua dòng lệnh, hãy làm như sau:

  1. Cắm một thiết bị đã bật tuỳ chọn cho nhà phát triển và tính năng gỡ lỗi qua USB.
  2. Cho phép máy tính gỡ lỗi thiết bị.
  3. Mở một shell trong thư mục gốc của kho lưu trữ androidx.
  4. Thay đổi thư mục thành framework/support.
  5. Chạy lệnh sau: ./gradlew window:window:connectedAndroidTest.
  6. Phân tích kết quả.

Để chạy các kiểm thử trong Android Studio, hãy làm như sau:

  1. Mở Android Studio
  2. Cắm một thiết bị đã bật tuỳ chọn cho nhà phát triển và tính năng gỡ lỗi qua USB.
  3. Cho phép máy tính gỡ lỗi thiết bị.
  4. Chuyển đến một kiểm thử trong thư viện cửa sổ của mô-đun cửa sổ.
  5. Mở một lớp kiểm thử và chạy bằng cách sử dụng các mũi tên màu xanh lục ở bên phải trình chỉnh sửa.

Ngoài ra, bạn có thể tạo một cấu hình trong Android Studio để chạy một phương thức kiểm thử, một lớp kiểm thử hoặc tất cả các kiểm thử trong một mô-đun.

Bạn có thể phân tích kết quả theo cách thủ công bằng cách xem đầu ra của shell. Một số kiểm thử sẽ bị bỏ qua nếu thiết bị không đáp ứng một số giả định nhất định. Kết quả được lưu ở một vị trí tiêu chuẩn và các nhà phân tích có thể viết một tập lệnh để tự động hoá việc phân tích kết quả.