Ứng dụng cho thiết bị có thể gập lại và thiết bị nhiều màn hình
Nhìn chung, ứng dụng không nên dựa vào các giá trị nhận dạng tĩnh hoặc logic phụ thuộc vào một số mã màn hình. Trong hầu hết các trường hợp, ứng dụng sẽ đổi kích thước và hoạt động trên nhiều màn hình, đồng thời hệ thống sẽ kiểm soát vị trí của ứng dụng. Ví dụ: để tạo trải nghiệm mới và độc đáo cho thiết bị có thể gập lại và chạy một ứng dụng đặc biệt trên màn hình ngoài khi thiết bị được gập lại.
Trong trường hợp này, SystemUI (hoặc một thành phần hệ thống khác) sẽ phát hiện nếp gập, xác định xem có phù hợp để thực hiện một hành động hay không, sau đó chạy hoạt động đích và chỉ định mã màn hình ngoài làm mục tiêu chạy. Ứng dụng không được phát hiện hành động này hoặc thực hiện bất kỳ hành động nào để phản hồi, sau đó chạy trên một màn hình cụ thể. Nói cách khác, đừng cho rằng những gì hoạt động trên một thiết bị sẽ hoạt động trên các thiết bị khác. Tóm lại, mã dành riêng cho thiết bị làm tăng tình trạng phân mảnh.
Hạn chế quyền truy cập vào màn hình
Nếu cấu hình thiết bị yêu cầu hạn chế quyền truy cập vào một hoặc nhiều màn hình, bạn nên sử dụng cờ Display#FLAG_PRIVATE để chỉ định các màn hình đó là riêng tư. Việc này sẽ hạn chế tất cả người dùng, trừ chủ sở hữu, thêm nội dung vào màn hình. Bất kỳ nỗ lực nào để chạy một hoạt động hoặc thêm một cửa sổ của bất kỳ ai ngoài chủ sở hữu đều dẫn đến SecurityException.
Nếu hệ thống sở hữu màn hình, thì hệ thống có thể thêm cửa sổ và chạy các hoạt động.
Ngoài ra, các thực thể được đặt trên màn hình luôn có thể truy cập vào màn hình đó. Nếu chủ sở hữu chạy một hoạt động trên màn hình, thì hoạt động đó có thể chạy các hoạt động khác trên màn hình này. Do đó, chủ sở hữu chịu trách nhiệm hạn chế quyền truy cập và chỉ cho phép các ứng dụng đáng tin cậy only.
Ngoài ra, các hạn chế khác được thêm vào màn hình ảo vì bất kỳ ứng dụng nào cũng có thể tạo một màn hình ảo mà không cần hiển thị cho người dùng. Nếu màn hình ảo không thuộc sở hữu của hệ thống, thì chỉ những hoạt động có allowEmbedded mới được cho phép và trình gọi phải có quyền ACTIVITY_EMBEDDING.
Để biết thêm thông tin, hãy xem trang web sau đây:
ActivityStackSupervisor#isCallerAllowedToLaunchOnDisplay()ActivityDisplay#isUidPresent()DisplayManagerService#isUidPresentOnDisplay()
Để kiểm soát có điều kiện việc chạy hoạt động, hãy sử dụng LaunchParamsController. Trình này sẽ chặn tất cả hoạt động chạy và cho phép một thành phần hệ thống sửa đổi các tham số dùng để chạy. Trình này có trong system_server.
Định cấu hình chế độ cài đặt cửa sổ màn hình và trang trí hệ thống
Trang trí hệ thống có thể
được định cấu hình cho mỗi màn hình trong DisplayWindowSettings. Cách triển khai thiết bị có thể cung cấp cấu hình mặc định trong /data/system/display_settings.xml.
Giá trị này xác định xem trang trí hệ thống (trình chạy, hình nền, thanh điều hướng và các cửa sổ trang trí khác) và IME có xuất hiện trên màn hình hay không.
Để biết thông tin chi tiết, hãy xem DisplayWindowSettings#shouldShowSystemDecorsLocked() và DisplayWindowSettings#shouldShowImeLocked().
Để xác định màn hình, hãy sử dụng mã nhận dạng duy nhất (giá trị mặc định này sử dụng DisplayInfo#uniqueId) hoặc mã cổng vật lý cho màn hình phần cứng (xem DisplayInfo#address).
Ví dụ: cấu hình màn hình sau đây cho phép trang trí hệ thống và IME trên màn hình mô phỏng:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <display-settings> <config identifier="0" /> <display name="overlay:1" shouldShowSystemDecors="true" shouldShowIme="true" /> </display-settings>
Trong ví dụ ở trên, uniqueId được dùng để xác định màn hình trong thuộc tính tên. Đối với màn hình mô phỏng, thuộc tính này là overlay:1.
Đối với màn hình tích hợp, giá trị mẫu có thể là "local:45354385242535243453".
Một lựa chọn khác là sử dụng thông tin cổng phần cứng và đặt identifier="1"
tương ứng với DisplayWindowSettings#IDENTIFIER_PORT, sau đó cập nhật
tên để sử dụng định dạng "port:<port_id>":
<?xmlversion='1.0' encoding='utf-8' standalone='yes' ?> <display-settings> <config identifier="1" /> <display name="port:12345" shouldShowSystemDecors="true" shouldShowIme="true" /> </display-settings>
Để biết thông tin chi tiết, hãy xem bài viết Giá trị nhận dạng màn hình tĩnh.
Để biết thêm thông tin, hãy xem trang web sau đây:
Chuyển đổi màn hình giữa các tác vụ phản chiếu và lưu trữ
Trong Android 17 trở lên, DisplayManager sử dụng cờ
FLAG_ALLOWS_CONTENT_MODE_SWITCH để kiểm soát xem màn hình có chuyển đổi
giữa các tác vụ phản chiếu và lưu trữ trong thời gian chạy hay không. Theo mặc định, cờ này được bật cho màn hình ngoài và tắt cho tất cả các màn hình khác.
Khi có FLAG_ALLOWS_CONTENT_MODE_SWITCH, DisplayManager sẽ theo dõi chế độ cài đặt bảo mật android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY để xác định xem có phản chiếu hay lưu trữ các tác vụ hay không. Mặc dù đây là logic mặc định, nhưng OEM có thể tuỳ chỉnh hành vi này.
Cấu trúc liên kết màn hình và chuyển động của con trỏ
Trong Android 17 trở lên, cấu trúc liên kết màn hình xác định vị trí tương đối của màn hình và hạn chế chuyển động của con trỏ chuột đối với tập hợp màn hình cụ thể trong cấu trúc liên kết.
WindowManager quyết định đưa màn hình vào cấu trúc liên kết và gọi DisplayManagerInternal.onDisplayBelongToTopologyChanged. DisplayManager kiểm tra DisplayTopologyCoordinator.isDisplayAllowedInTopology trước khi thêm màn hình. Theo mặc định, nếu màn hình cục bộ có thể lưu trữ các tác vụ, thì hệ thống sẽ thêm các màn hình đó.
Nếu có nhiều màn hình công khai có thể lưu trữ các tác vụ, thì quyết định đưa màn hình mặc định vào sẽ do trình cung cấp boolean shouldIncludeDefaultDisplayInTopology xử lý. Trình này được truyền đến DisplayTopologyCoordinator. Nếu màn hình mặc định là màn hình công khai duy nhất có thể lưu trữ các tác vụ, thì màn hình đó luôn nằm trong cấu trúc liên kết. Trong AOSP, trình cung cấp boolean chỉ trả về true nếu màn hình mặc định hỗ trợ tính năng cửa sổ kiểu máy tính hoặc nếu chế độ cài đặt bảo mật Settings.Secure.INCLUDE_DEFAULT_DISPLAY_IN_TOPOLOGY là true.
Ứng dụng truy vấn cấu trúc liên kết hiện tại bằng cách sử dụng DisplayManager.getDisplayTopology và phản ứng với các thay đổi đối với cấu trúc liên kết bằng cách đăng ký trình nghe bằng DisplayManager.registerTopologyListener.