Thông tin cập nhật về các khu vực dành riêng cho màn hình này được cung cấp trên trang này.
Thành phần trang trí hệ thống
Android 10 bổ sung tính năng hỗ trợ định cấu hình màn hình phụ để hiển thị một số thành phần trang trí hệ thống, chẳng hạn như hình nền, thanh điều hướng và trình chạy. Theo mặc định, màn hình chính sẽ hiển thị tất cả thành phần trang trí hệ thống và màn hình phụ sẽ hiển thị những thành phần được bật (không bắt buộc). Bạn có thể thiết lập tính năng hỗ trợ cho trình chỉnh sửa phương thức nhập (IME) riêng biệt với các thành phần trang trí hệ thống khác.
Sử dụng DisplayWindowSettings#setShouldShowSystemDecorsLocked để thêm tính năng hỗ trợ cho các thành phần trang trí hệ thống trên một màn hình cụ thể hoặc cung cấp giá trị mặc định trong /data/system/display_settings.xml. Để xem ví dụ,
hãy xem phần Cài đặt cửa sổ hiển thị.
Trong Android 17 trở lên, tính năng hỗ trợ thành phần trang trí hệ thống của màn hình có thể thay đổi một cách linh hoạt. Nếu màn hình có cờ FLAG_ALLOWS_CONTENT_MODE_SWITCH, hệ thống sẽ cho phép người dùng quyết định xem màn hình đó lưu trữ ứng dụng hay phản chiếu một màn hình khác. Hệ thống chỉ sử dụng các thành phần trang trí hệ thống nếu người dùng quyết định sử dụng màn hình để lưu trữ ứng dụng. Các thành phần hệ thống, chẳng hạn như Giao diện người dùng hệ thống và trình chạy OEM, chịu trách nhiệm tạo và hiển thị các thành phần trang trí hệ thống. Để thêm hoặc xoá các thành phần trang trí hệ thống một cách linh hoạt, cũng như để khởi chạy hoặc giải phóng các cấu trúc trên mỗi màn hình, các thành phần này phải đăng ký thực thể IDisplayWindowListener và triển khai các phương thức IDisplayWindowListener.onDisplayAddSystemDecorations và IDisplayWindowListener.onDisplayRemoveSystemDecorations.
IDisplayWindowListener là một API ẩn chỉ dành cho các thành phần hệ thống.
Triển khai
DisplayWindowSettings#setShouldShowSystemDecorsLocked cũng được hiển thị trong WindowManager#setShouldShowSystemDecors để thử nghiệm. Việc kích hoạt phương thức này với ý định bật các thành phần trang trí hệ thống sẽ không thêm các cửa sổ trang trí bị thiếu trước đó hoặc xoá các cửa sổ đó nếu chúng đã có trước đó. Trong hầu hết các trường hợp, việc thay đổi tính năng hỗ trợ thành phần trang trí hệ thống chỉ có hiệu lực đầy đủ sau khi thiết bị khởi động lại.
Việc kiểm tra tính năng hỗ trợ thành phần trang trí hệ thống trong toàn bộ mã nguồn WindowManager thường diễn ra thông qua DisplayContent#supportsSystemDecorations, trong khi việc kiểm tra các dịch vụ bên ngoài (chẳng hạn như Giao diện người dùng hệ thống để kiểm tra xem có nên hiển thị thanh điều hướng hay không) sẽ sử dụng WindowManager#shouldShowSystemDecors.
Để hiểu rõ những gì được kiểm soát bằng chế độ cài đặt này, hãy khám phá các điểm gọi của những phương thức này.
Cửa sổ trang trí giao diện người dùng hệ thống
Android 10 chỉ thêm tính năng hỗ trợ cửa sổ trang trí hệ thống cho thanh điều hướng vì thanh điều hướng là yếu tố cần thiết để di chuyển giữa các hoạt động và ứng dụng. Theo mặc định, thanh điều hướng sẽ hiển thị các thành phần hỗ trợ Quay lại và Trang chủ. Thanh điều hướng chỉ được đưa vào nếu màn hình đích hỗ trợ các thành phần trang trí hệ thống (xem DisplayWindowSettings).
Thanh trạng thái là một cửa sổ hệ thống phức tạp hơn vì thanh trạng thái cũng chứa Ngăn thông báo, Cài đặt nhanh và Màn hình khoá. Trong Android 10, thanh trạng thái không được hỗ trợ trên màn hình phụ. Do đó, thông báo, chế độ cài đặt và khoá bảo vệ đầy đủ chỉ có trên màn hình chính.
Cửa sổ hệ thống Tổng quan hoặc Gần đây không được hỗ trợ trên màn hình phụ. Trong Android 10, AOSP chỉ hiển thị mục Gần đây trên màn hình mặc định và chứa các hoạt động từ tất cả màn hình. Khi được chạy từ mục Gần đây, một hoạt động trên màn hình phụ sẽ được đưa lên phía trước trên màn hình đó theo mặc định. Phương pháp này có một số vấn đề đã biết, chẳng hạn như không cập nhật ngay khi ứng dụng xuất hiện trên các màn hình khác.
Triển khai
Để triển khai các tính năng bổ sung của Giao diện người dùng hệ thống, nhà sản xuất thiết bị nên sử dụng một thành phần Giao diện người dùng hệ thống duy nhất để theo dõi việc thêm hoặc xoá màn hình và trình bày nội dung thích hợp.
Thành phần Giao diện người dùng hệ thống hỗ trợ Nhiều màn hình (MD) phải xử lý các trường hợp sau:
- Khởi chạy nhiều màn hình khi khởi động
- Màn hình được thêm vào trong thời gian chạy
- Màn hình bị xoá trong thời gian chạy
Khi Giao diện người dùng hệ thống phát hiện việc thêm màn hình trước WindowManager, hệ thống sẽ tạo ra tình huống tương tranh. Bạn có thể tránh tình trạng này bằng cách triển khai lệnh gọi lại tuỳ chỉnh từ WindowManager đến Giao diện người dùng hệ thống khi thêm màn hình thay vì đăng ký các sự kiện DisplayManager.DisplayListener. Để tham khảo cách triển khai, hãy xem CommandQueue.Callbacks#onDisplayAddSystemDecorations để biết tính năng hỗ trợ thanh điều hướng và WallpaperManagerInternal#onDisplayAddSystemDecorations để biết hình nền.
Ngoài ra, Android 10 còn cung cấp các bản cập nhật sau:
- Lớp
NavigationBarControllerkiểm soát tất cả chức năng dành riêng cho thanh điều hướng. - Để xem thanh điều hướng tuỳ chỉnh, hãy xem
CarStatusBar. TYPE_NAVIGATION_BARkhông còn bị giới hạn ở một thực thể duy nhất và có thể được sử dụng trên mỗi màn hình.IWindowManager#hasNavigationBarđược cập nhật để chỉ bao gồm tham sốdisplayIdcho Giao diện người dùng hệ thống.
Trình chạy
Trong Android 10, theo mặc định, mỗi màn hình được định cấu hình để hỗ trợ các thành phần trang trí hệ thống đều có một ngăn xếp trang chủ riêng cho các hoạt động của trình chạy có loại WindowConfiguration#ACTIVITY_TYPE_HOME. Mỗi màn hình sử dụng một thực thể riêng của hoạt động trình chạy:


Hình 1. Ví dụ về trình chạy nhiều màn hình cho platform/development/samples/MultiDisplay.
Hầu hết các trình chạy hiện có đều không hỗ trợ nhiều thực thể và không được tối ưu hoá cho kích thước màn hình lớn. Ngoài ra, người dùng thường mong đợi một trải nghiệm khác trên màn hình phụ/màn hình ngoài. Để cung cấp một hoạt động riêng cho màn hình phụ, Android 10 đã giới thiệu danh mục SECONDARY_HOME trong bộ lọc ý định. Các thực thể của hoạt động này được sử dụng trên tất cả các màn hình hỗ trợ các thành phần trang trí hệ thống, một thực thể cho mỗi màn hình.
<activity>
...
<intent-filter>
<category android:name="android.intent.category.SECONDARY_HOME" />
...
</intent-filter>
</activity>Hoạt động phải có một chế độ chạy cho phép tồn tại nhiều thực thể và có thể thích ứng với nhiều kích thước màn hình. Chế độ chạy không được là singleInstance hoặc singleTask.
Triển khai
Trong Android 10, RootActivityContainer#startHomeOnDisplay sẽ tự động chọn thành phần và ý định mong muốn tuỳ thuộc vào màn hình chạy màn hình chính. RootActivityContainer#resolveSecondaryHomeActivity
chứa logic để tra cứu thành phần hoạt động của trình chạy tuỳ thuộc vào trình chạy hiện được chọn và có thể sử dụng trình chạy mặc định của hệ thống nếu cần (xem ActivityTaskManagerService#getSecondaryHomeIntent).
Hạn chế về bảo mật
Ngoài các hạn chế áp dụng cho các hoạt động trên màn hình phụ, để tránh trường hợp ứng dụng độc hại tạo màn hình ảo có bật các thành phần trang trí hệ thống và đọc thông tin nhạy cảm của người dùng từ bề mặt, trình chạy chỉ xuất hiện trên các màn hình ảo do hệ thống sở hữu. Trình chạy không hiển thị nội dung trên các màn hình ảo không phải của hệ thống.
Hình nền
Trong Android 10 trở lên, hình nền được hỗ trợ trên màn hình phụ:


Hình 2. Hình nền động trên màn hình bên trong (ở trên) và màn hình bên ngoài (ở dưới).
Nhà phát triển có thể khai báo tính năng hỗ trợ hình nền bằng cách cung cấp android:supportsMultipleDisplays="true" trong định nghĩa XML WallpaperInfo. Nhà phát triển hình nền cũng phải tải các thành phần bằng cách sử dụng bối cảnh hiển thị trong WallpaperService.Engine#getDisplayContext.
Khung sẽ tạo một thực thể WallpaperService.Engine cho mỗi màn hình, vì vậy, mỗi công cụ đều có bề mặt và bối cảnh hiển thị riêng. Nhà phát triển cần đảm bảo rằng mỗi công cụ có thể vẽ một cách độc lập, ở các tốc độ khung hình khác nhau, tuân thủ VSync.
Chọn hình nền cho từng màn hình
Android 10 không hỗ trợ trực tiếp nền tảng để chọn hình nền cho từng màn hình. Để thực hiện việc này, bạn cần có một giá trị nhận dạng màn hình ổn định để duy trì chế độ cài đặt hình nền trên mỗi màn hình.
Display#getDisplayId là động, vì vậy, không có gì đảm bảo rằng màn hình thực sẽ có cùng mã nhận dạng sau khi khởi động lại.
Tuy nhiên, Android 10 đã thêm DisplayInfo.mAddress, chứa các giá trị nhận dạng ổn định cho màn hình thực và có thể được sử dụng để triển khai đầy đủ trong tương lai. Rất tiếc, đã quá muộn để triển khai logic cho Android 10. Giải pháp được đề xuất:
- Sử dụng lớp
WallpaperManagerđể đặt hình nền.WallpaperManagerđược lấy từ đối tượngContextvà mỗi đối tượngContextcó thông tin về màn hình tương ứng (Context#getDisplay/getDisplayId). Do đó, bạn có thể lấydisplayIdtừ thực thểWallpaperManagermà không cần thêm phương thức mới. - Ở phía khung, hãy sử dụng
displayIdlấy từ đối tượngContextvà ánh xạ đối tượng đó đến một giá trị nhận dạng tĩnh (chẳng hạn như cổng của màn hình thực). Sử dụng giá trị nhận dạng tĩnh để duy trì hình nền đã chọn.
Giải pháp thay thế này sử dụng các cách triển khai hiện có cho trình chọn hình nền. Nếu trình chọn hình nền được mở trên một màn hình cụ thể và sử dụng đúng bối cảnh, thì khi gọi để đặt hình nền, hệ thống có thể tự động xác định màn hình đó.
Nếu cần đặt hình nền cho một màn hình khác với màn hình hiện tại
display, hãy tạo đối tượng Context mới cho màn hình đích
(Context#createDisplayContext) và lấy thực thể
WallpaperManager từ màn hình đó.
Hạn chế về bảo mật
Hệ thống sẽ không hiển thị hình nền trên các màn hình ảo mà hệ thống không sở hữu. Điều này là do lo ngại về bảo mật rằng một ứng dụng độc hại có thể tạo màn hình ảo có bật tính năng hỗ trợ thành phần trang trí hệ thống và đọc thông tin nhạy cảm của người dùng từ bề mặt (chẳng hạn như ảnh cá nhân).
Triển khai
Trong Android 10, các giao diện IWallpaperConnection#attachEngine và IWallpaperService#attach chấp nhận tham số displayId để tạo kết nối trên mỗi màn hình.
WallpaperManagerService.DisplayConnector đóng gói một công cụ và kết nối hình nền trên mỗi màn hình. Trong WindowManager, bộ điều khiển hình nền được tạo cho mỗi đối tượng DisplayContent khi xây dựng thay vì một WallpaperController duy nhất cho tất cả màn hình.
Một số cách triển khai phương thức WallpaperManager công khai (chẳng hạn như
WallpaperManager#getDesiredMinimumWidth) đã được cập nhật để tính toán
và cung cấp thông tin cho các màn hình tương ứng.
WallpaperInfo#supportsMultipleDisplays và thuộc tính tài nguyên tương ứng đã được thêm vào để nhà phát triển ứng dụng có thể báo cáo những hình nền đã sẵn sàng cho nhiều màn hình.
Nếu dịch vụ hình nền xuất hiện trên màn hình mặc định không hỗ trợ nhiều màn hình, thì hệ thống sẽ hiển thị hình nền mặc định trên màn hình phụ:

Hình 3. Logic dự phòng hình nền cho màn hình phụ.
Bật tính năng hỗ trợ hình nền động
Trong Android 10 trở lên (API 29), nhà phát triển có thể sử dụng thuộc tính android:supportsMultipleDisplays
để cho biết liệu hình nền của họ có thể trải rộng trên nhiều màn hình hay không. Trong môi trường cửa sổ kiểu máy tính, nơi có nhiều tác vụ, việc kết xuất hình nền động trên màn hình ngoài có thể ảnh hưởng đáng kể đến GPU và chi phí bộ nhớ.
Để bảo tồn tài nguyên hệ thống, theo mặc định, hệ thống sẽ không kết xuất hình nền động trên các màn hình được kết nối. Khi hình nền động bị hạn chế bởi cấu hình hệ thống hoặc tệp kê khai của ứng dụng, hệ thống sẽ kết xuất hình nền tĩnh dự phòng.
OEM có thể điều chỉnh trải nghiệm này bằng cách bật tính năng hỗ trợ hình nền động cho phần cứng cao cấp hoặc tuỳ chỉnh hình nền tĩnh dự phòng để có giao diện mang thương hiệu.
Nếu phần cứng của bạn có thể kết xuất nhiều thực thể hình nền động, hãy ghi đè cấu hình sau:
| Đường dẫn đến tài nguyên | frameworks/base/core/res/res/values/config.xml |
|---|---|
| Tên cấu hình | config_isLiveWallpaperSupportedInDesktopExperience |
Tuỳ chỉnh hình nền dự phòng
Nếu hình nền động bị tắt hoặc không được nhà cung cấp hỗ trợ, hệ thống sẽ sử dụng thành phần mặc định. Bạn có thể trỏ thành phần này đến nhà cung cấp hình nền tĩnh của riêng mình:
| Đường dẫn đến tài nguyên | frameworks/base/core/res/res/values/config.xml |
|---|---|
| Tên cấu hình | fallback_wallpaper_component |
Triển khai tính năng hỗ trợ hình nền
Để áp dụng những thay đổi này, hãy sử dụng lớp phủ tài nguyên trong thời gian xây dựng trong thư mục dành riêng cho thiết bị của bạn, thường
là device/<vendor>/<product>/overlay/frameworks/base/core/res/res/values/.