Hỗ trợ quảng cáo hiển thị

Dưới đây là nội dung cập nhật cho các khu vực hiển thị cụ thể này:

Đổi kích thước hoạt động và màn hình

Để cho biết rằng một ứng dụng có thể không hỗ trợ chế độ nhiều cửa sổ hoặc đổi kích thước, hoạt động sử dụng thuộc tính resizeableActivity=false. Phổ biến các vấn đề mà ứng dụng gặp phải khi hoạt động được đổi kích thước bao gồm:

  • Một hoạt động có thể có cấu hình khác với ứng dụng hoặc ứng dụng khác thành phần không trực quan. Một lỗi thường gặp là đọc chỉ số hiển thị qua ứng dụng ngữ cảnh. Các giá trị trả về sẽ không được điều chỉnh thành các chỉ số về khu vực hiển thị trong nơi hiển thị một hoạt động.
  • Một hoạt động có thể không xử lý được sự cố và đổi kích thước, hiển thị giao diện người dùng bị méo hình, hoặc mất trạng thái do chạy lại mà không lưu trạng thái của thực thể.
  • Ứng dụng có thể cố gắng sử dụng toạ độ đầu vào tuyệt đối (thay vì các toạ độ đó tương ứng với vị trí cửa sổ), điều này có thể phá vỡ giá trị nhập trong nhiều cửa sổ.

Trong Android 7 (trở lên), bạn có thể thiết lập một ứng dụng resizeableActivity=false để luôn chạy ở chế độ toàn màn hình. Ngang bằng trong trường hợp này, nền tảng sẽ ngăn các hoạt động không thể đổi kích thước bị tách ra màn hình. Nếu người dùng cố gắng gọi một hoạt động không thể đổi kích thước từ trình chạy khi đã ở chế độ chia đôi màn hình, nền tảng thoát khỏi chế độ chia đôi màn hình và khởi chạy hoạt động không thể đổi kích thước ở chế độ toàn màn hình.

Ứng dụng đã đặt rõ ràng thuộc tính này thành false trong phần không được chạy tệp kê khai ở chế độ nhiều cửa sổ, trừ trường hợp khả năng tương thích chế độ được áp dụng:

  • Cùng một cấu hình được áp dụng cho quy trình chứa tất cả các hoạt động và thành phần không hoạt động.
  • Cấu hình đã áp dụng đáp ứng các yêu cầu của CDD để tương thích với ứng dụng màn hình.

Trong Android 10, nền tảng này vẫn ngăn chặn hoạt động không thể đổi kích thước chuyển sang chế độ chia đôi màn hình, nhưng chúng có thể tạm thời được điều chỉnh theo tỷ lệ nếu hoạt động đã khai báo một hướng hoặc khung hình cố định . Nếu không, hoạt động sẽ đổi kích thước để lấp đầy toàn bộ màn hình như trong Android 9 trở xuống.

Cách triển khai mặc định áp dụng chính sách sau:

Khi một hoạt động được khai báo là không tương thích với chế độ nhiều cửa sổ thông qua việc sử dụng thuộc tính android:resizeableActivity và khi thuộc tính đó đáp ứng một trong các điều kiện được mô tả dưới đây, thì khi cấu hình màn hình phải thay đổi, thì hoạt động và quy trình được lưu bằng cấu hình ban đầu và người dùng được cung cấp một thuộc tính tương tác để chạy lại quy trình ứng dụng để sử dụng cấu hình màn hình đã cập nhật.

  • Là hướng cố định thông qua việc áp dụng android:screenOrientation
  • Ứng dụng có tỷ lệ khung hình tối đa hoặc tối thiểu mặc định theo cấp độ API nhắm đến hoặc khai báo tỷ lệ khung hình một cách rõ ràng

Hình này thể hiện một hoạt động không thể đổi kích thước với tỷ lệ khung hình đã khai báo. Khi gập thiết bị, cửa sổ sẽ được thu nhỏ cho vừa với diện tích trong khi duy trì tỷ lệ khung hình bằng cách sử dụng hiệu ứng hòm thư thích hợp. Ngoài ra, một tuỳ chọn khởi động lại hoạt động được cung cấp cho người dùng mỗi khi khu vực hiển thị hoạt động sẽ bị thay đổi.

Khi thiết bị mở ra, cấu hình, kích thước và tỷ lệ khung hình của hoạt động không thay đổi nhưng tuỳ chọn khởi động lại hoạt động sẽ được hiển thị.

Khi resizeableActivity không được đặt (hoặc được đặt thành true), ứng dụng này hỗ trợ đầy đủ tính năng đổi kích thước.

Triển khai

Một hoạt động không thể đổi kích thước có hướng hoặc tỷ lệ khung hình cố định được gọi chế độ tương thích với kích thước (SCM) trong mã. Điều kiện này được xác định trong ActivityRecord#shouldUseSizeCompatMode(). Khi một hoạt động SCM đang thì cấu hình liên quan đến màn hình (chẳng hạn như kích thước hoặc mật độ) được cố định trong cấu hình ghi đè được yêu cầu, để hoạt động không còn phụ thuộc trên cấu hình hiển thị hiện tại.

Nếu hoạt động SCM không thể lấp đầy toàn bộ màn hình, hoạt động đó sẽ được căn chỉnh trên cùng và chính giữa theo chiều ngang. Giới hạn hoạt động được tính bằng AppWindowToken#calculateCompatBoundsTransformation().

Khi một hoạt động SCM sử dụng cấu hình màn hình khác với cấu hình vùng chứa (ví dụ: màn hình được đổi kích thước hoặc hoạt động chuyển sang vùng chứa khác ), ActivityRecord#inSizeCompatMode() là đúng và SizeCompatModeActivityController (trong Giao diện người dùng hệ thống) nhận được lệnh gọi lại để cho thấy nút khởi động lại quy trình.

Hiển thị kích thước và tỷ lệ khung hình

Android 10 hỗ trợ các tỷ lệ khung hình mới từ tỷ lệ màn hình dài và mỏng đến tỷ lệ 1:1. Các ứng dụng có thể xác định ApplicationInfo#maxAspectRatioApplicationInfo#minAspectRatio của màn hình có thể xử lý.

tỷ lệ ứng dụng trong Android 10

Hình 1. Ví dụ về tỷ lệ ứng dụng được hỗ trợ trong Android 10

Quá trình triển khai thiết bị có thể có màn hình phụ kèm theo kích thước và độ phân giải nhỏ hơn các độ phân giải mà Android 9 yêu cầu và thấp hơn (tối thiểu là 2, 5 chiều rộng hoặc chiều cao inch, tối thiểu là 320 DP cho smallestScreenWidth), nhưng chỉ có thể đặt những hoạt động chọn tham gia hỗ trợ những màn hình nhỏ này ở đó.

Ứng dụng có thể chọn tham gia bằng cách khai báo kích thước tối thiểu được hỗ trợ nhỏ hơn hoặc bằng kích thước hiển thị mục tiêu. Sử dụng android:minHeight và Thuộc tính bố cục hoạt động android:minWidth trong AndroidManifest để thực hiện việc này.

Chính sách hiển thị

Android 10 tách riêng và di chuyển một số màn hình từ hoạt động triển khai WindowManagerPolicy mặc định trong PhoneWindowManager cho các lớp trên mỗi màn hình, chẳng hạn như:

  • Trạng thái hiển thị và chế độ xoay
  • Một số phím và tính năng theo dõi sự kiện chuyển động
  • Cửa sổ trang trí và giao diện người dùng hệ thống

Trong Android 9 (trở xuống), lớp PhoneWindowManager đã xử lý chính sách hiển thị, trạng thái và chế độ cài đặt, xoay, khung cửa sổ trang trí theo dõi và nhiều tính năng khác. Android 10 chuyển hầu hết các tính năng này sang lớp DisplayPolicy, ngoại trừ lớp theo dõi xoay vòng, vốn có đã được chuyển đến DisplayRotation.

Hiển thị chế độ cài đặt cửa sổ

Trong Android 10, báo cáo có thể định cấu hình trên mỗi màn hình đã được mở rộng chế độ cài đặt cửa sổ bao gồm:

  • Chế độ hiển thị cửa sổ mặc định
  • Quét quá giá trị
  • Chế độ xoay và xoay người dùng
  • Chế độ kích thước, mật độ và tỷ lệ bắt buộc
  • Chế độ xoá nội dung (khi màn hình bị xoá)
  • Hỗ trợ trang trí hệ thống và IME

Lớp DisplayWindowSettings chứa các chế độ cài đặt cho những . Chúng được lưu trữ trên đĩa trong phân vùng /data trong display_settings.xml mỗi khi thay đổi một chế độ cài đặt. Cho chi tiết, xem DisplayWindowSettings.AtomicFileStorageDisplayWindowSettings#writeSettings(). Nhà sản xuất thiết bị có thể cung cấp các giá trị mặc định bằng display_settings.xml cho thiết bị của họ . Tuy nhiên, vì tệp được lưu trữ trong /data, có thể cần thêm logic để khôi phục tệp nếu bị xoá bằng quy trình xoá.

Theo mặc định, Android 10 sử dụng DisplayInfo#uniqueId làm giá trị nhận dạng cho màn hình khi duy trì phần cài đặt. Bạn phải điền uniqueId cho mọi màn hình. Ngang bằng ngoài ra, định dạng này ổn định cho màn hình thực và màn hình mạng. Bạn cũng có thể sử dụng cổng của màn hình thực làm giá trị nhận dạng, có thể được đặt trong DisplayWindowSettings#mIdentifier. Sau mỗi lần ghi, tất cả các chế độ cài đặt được ghi nên có thể cập nhật khoá được dùng cho mục nhập hiển thị trong bộ nhớ. Để biết thông tin chi tiết, hãy xem Mã nhận dạng hiển thị tĩnh.

Các chế độ cài đặt vẫn tồn tại trong thư mục /data trong quá khứ lý do. Ban đầu, chúng được dùng để duy trì các chế độ cài đặt do người dùng đặt, chẳng hạn như xoay màn hình.

Mã nhận dạng hiển thị tĩnh

Android 9 (trở xuống) không cung cấp giá trị nhận dạng ổn định cho màn hình trong khung. Khi một màn hình được thêm vào hệ thống, Display#mDisplayId hoặc DisplayInfo#displayId cũ là được tạo cho màn hình đó bằng cách tăng bộ đếm tĩnh. Nếu hệ thống đã thêm và xoá cùng một màn hình, dẫn đến một mã nhận dạng khác.

Nếu một thiết bị có nhiều màn hình từ lúc khởi động, thì các màn hình đó có thể gán các giá trị nhận dạng khác nhau, tuỳ thuộc vào thời gian. Trong khi Android 9 (và trước đó) bao gồm DisplayInfo#uniqueId, không chứa đủ thông tin để phân biệt giữa các màn hình vì màn hình thực tế được xác định là local:0 hoặc local:1 để đại diện cho màn hình tích hợp và màn hình bên ngoài.

Android 10 thay đổi DisplayInfo#uniqueId để thêm giá trị nhận dạng ổn định và để phân biệt giữa cục bộ, mạng và màn hình ảo.

Loại hiển thị Định dạng
Địa phương
local:<stable-id>
Mạng
network:<mac-address>
Qua mạng
virtual:<package-name-and-name>

Ngoài các bản cập nhật lên uniqueId, DisplayInfo.address chứa DisplayAddress, một giá trị nhận dạng màn hình ổn định khi khởi động lại. Trong Android 10, DisplayAddress hỗ trợ thẻ thực và màn hình mạng. DisplayAddress.Physical có chứa một ổn định mã hiển thị (giống như trong uniqueId) và có thể được tạo bằng DisplayAddress#fromPhysicalDisplayId().

Android 10 cũng cung cấp một phương thức thuận tiện để tải thông tin cổng (Physical#getPort()). Phương pháp này có thể được sử dụng trong khung để xác định tĩnh màn hình. Ví dụ: tên này được dùng trong DisplayWindowSettings). DisplayAddress.Network chứa địa chỉ MAC và có thể được tạo bằng DisplayAddress#fromMacAddress().

Những nội dung bổ sung này cho phép nhà sản xuất thiết bị xác định màn hình ở trạng thái tĩnh chế độ thiết lập nhiều màn hình cũng như định cấu hình nhiều chế độ cài đặt và tính năng hệ thống bằng cách sử dụng mã nhận dạng hiển thị tĩnh, chẳng hạn như cổng cho màn hình thực. Các đã bị ẩn và chỉ sử dụng trong system_server.

Được cung cấp mã hiển thị HWC (có thể mờ và không phải lúc nào cũng ổn định), phương thức trả về số cổng 8 bit (dành riêng cho nền tảng) xác định trình kết nối vật lý cho đầu ra màn hình cũng như blob EDID của màn hình. SurfaceFlinger trích xuất thông tin về nhà sản xuất hoặc kiểu máy từ EDID sang tạo mã hiển thị 64 bit ổn định được hiển thị với khung. Nếu phương thức này không được hỗ trợ hoặc gặp lỗi, SurfaceFlinger sẽ quay lại chế độ MD cũ, trong đó DisplayInfo#address rỗng và DisplayInfo#uniqueId được mã hoá cứng, như mô tả ở trên.

Để xác minh rằng tính năng này được hỗ trợ, hãy chạy mã:

$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"

Sử dụng nhiều hơn 2 màn hình

Trong Android 9 (trở xuống), SurfaceFlinger và DisplayManagerService giả định sự tồn tại của tối đa hai màn hình thực tế có mã nhận dạng được cố định giá trị trong mã là 0 và 1.

Bắt đầu từ Android 10, SurfaceFlinger có thể tận dụng Hardware Composer API (API Composer phần cứng) (HWC) để tạo mã hiển thị ổn định, cho phép API này quản lý một số lượng tuỳ ý các màn hình thực tế. Để tìm hiểu thêm, hãy xem Mã nhận dạng hiển thị tĩnh.

Khung này có thể tra cứu mã thông báo IBinder để hiển thị thông qua SurfaceControl#getPhysicalDisplayToken sau khi nhận được mã hiển thị 64 bit từ SurfaceControl#getPhysicalDisplayIds hoặc từ một sự kiện nóng DisplayEventReceiver.

Trên Android 10 (trở xuống), màn hình bên trong chính là TYPE_INTERNAL và tất cả các màn hình phụ đều bị gắn cờ là TYPE_EXTERNAL bất kể loại kết nối là gì. Do đó, màn hình bên trong bổ sung được coi là màn hình bên ngoài. Để giải quyết vấn đề này, mã dành riêng cho thiết bị có thể đưa ra các giả định về DisplayAddress.Physical#getPort nếu đã biết HWC và quy trình phân bổ cổng logic dễ dự đoán.

Hạn chế này sẽ được loại bỏ trên Android 11 (trở lên).

  • Trong Android 11, màn hình đầu tiên được báo cáo trong quá trình khởi động là màn hình chính. Loại kết nối (nội bộ so với bên ngoài) không liên quan. Tuy nhiên, vẫn đúng là không thể ngắt kết nối màn hình chính và tuân theo đó phải là màn hình nội bộ trong thực tế. Lưu ý rằng một số điện thoại có thể gập lại có nhiều màn hình nội bộ.
  • Màn hình phụ được phân loại chính xác là Display.TYPE_INTERNAL hoặc Display.TYPE_EXTERNAL (trước đây gọi là Display.TYPE_BUILT_INDisplay.TYPE_HDMI) tuỳ thuộc vào loại kết nối của chúng.

Triển khai

Trong Android 9 trở xuống, màn hình được xác định bằng mã nhận dạng 32 bit, trong đó 0 là màn hình trong, 1 là màn hình bên ngoài, [2, INT32_MAX] là màn hình ảo HWC và -1 biểu thị màn hình không hợp lệ hoặc màn hình ảo không phải HWC.

Kể từ Android 10, màn hình sẽ có phiên bản ổn định và mã nhận dạng cố định, cho phép SurfaceFlinger và DisplayManagerService để theo dõi nhiều hơn hai màn hình và nhận dạng các màn hình đã nhìn thấy trước đó. Nếu HWC hỗ trợ IComposerClient.getDisplayIdentificationData và cung cấp màn hình dữ liệu nhận dạng, SurfaceFlinger phân tích cú pháp cấu trúc EDID và phân bổ ổn định Mã hiển thị 64 bit cho màn hình thực và màn hình ảo HWC. Các mã nhận dạng này được biểu thị bằng loại tuỳ chọn, trong đó giá trị rỗng biểu thị màn hình không hợp lệ hoặc ảo không phải HWC màn hình. Nếu không hỗ trợ HWC, SurfaceFlinger sẽ quay lại hoạt động cũ với mức nhất là hai màn hình thực.

Tiêu điểm trên mỗi màn hình

Để hỗ trợ nhiều nguồn đầu vào cùng lúc nhắm đến từng màn hình , bạn có thể định cấu hình Android 10 để hỗ trợ nhiều cửa sổ được lấy tiêu điểm, tối đa một cửa sổ trên mỗi màn hình. Điều này chỉ dành cho các báo cáo đặc biệt các loại thiết bị khi nhiều người dùng tương tác với cùng một thiết bị trên cùng một lúc thời gian và sử dụng các phương thức nhập hoặc thiết bị khác nhau, chẳng hạn như Android Ô tô.

Bạn không nên bật tính năng này cho các thiết bị thông thường, bao gồm cả thiết bị nhiều màn hình hoặc các thiết bị được dùng để xem máy tính của bạn. Điều này chủ yếu là do lo ngại về bảo mật có thể khiến người dùng để thắc mắc cửa sổ nào có tâm điểm nhập.

Hãy tưởng tượng người dùng nhập thông tin bảo mật vào trường nhập dữ liệu văn bản, có thể là đăng nhập vào ứng dụng ngân hàng hoặc nhập văn bản có chứa nhạy cảm của bạn. Một ứng dụng độc hại có thể tạo màn hình ảo bằng để thực thi hoạt động, cũng với trường nhập văn bản. Hợp pháp và các hoạt động độc hại có tâm điểm và cả hai đều hiển thị chỉ báo nhập đang hoạt động (nhấp nháy con trỏ).

Tuy nhiên, vì phương thức nhập từ bàn phím (phần cứng hoặc phần mềm) sẽ được nhập vào chỉ hoạt động trên cùng (ứng dụng được phát hành gần đây nhất), theo tạo màn hình ảo ẩn, một ứng dụng độc hại có thể thu thập thông tin hoạt động đầu vào của người dùng, thậm chí khi dùng bàn phím phần mềm trên màn hình chính của thiết bị.

Sử dụng com.android.internal.R.bool.config_perDisplayFocusEnabled để đặt tiêu điểm trên mỗi màn hình.

Khả năng tương thích

Vấn đề: Trong Android 9 trở xuống, tối đa một cửa sổ trong có tiêu điểm tại một thời điểm.

Giải pháp: Trong trường hợp hiếm hoi khi hai cửa sổ từ cùng một quy trình sẽ được tập trung, hệ thống chỉ cung cấp tiêu điểm cho cửa sổ cao hơn thứ tự Z. Quy định hạn chế này sẽ bị loại bỏ đối với những ứng dụng nhắm đến Android 10, tại thời điểm đó dự kiến rằng chúng có thể hỗ trợ nhiều cửa sổ được lấy tiêu điểm cùng một lúc.

Triển khai

WindowManagerService#mPerDisplayFocusEnabled kiểm soát khả năng sử dụng tính năng này. Sau ActivityManager, ActivityDisplay#getFocusedStack() hiện được sử dụng thay vì ngôn ngữ chung theo dõi ở một biến. ActivityDisplay#getFocusedStack() xác định tiêu điểm dựa trên thứ tự Z thay vì lưu giá trị vào bộ nhớ đệm. Điều này là để chỉ có một nguồn là WindowManager, cần theo dõi thứ tự Z của các hoạt động.

ActivityStackSupervisor#getTopDisplayFocusedStack() sẽ mất một phương pháp tương tự cho những trường hợp đó khi ngăn xếp tập trung ở trên cùng trong hệ thống phải được xác định. Các ngăn xếp được di chuyển từ trên xuống dưới để tìm kiếm ngăn xếp đủ điều kiện đầu tiên.

InputDispatcher hiện có thể có nhiều cửa sổ được lấy tiêu điểm (một mã cho mỗi màn hình). Nếu một sự kiện đầu vào là sự kiện hiển thị cụ thể, thì sự kiện đó sẽ được gửi đi vào cửa sổ được đặt tiêu điểm trên màn hình tương ứng. Nếu không, đơn đặt hàng sẽ được gửi đi vào cửa sổ được đặt tiêu điểm trong màn hình được lấy tiêu điểm, đây là màn hình mà người dùng tương tác gần đây nhất.

Xem InputDispatcher::mFocusedWindowHandlesByDisplayInputDispatcher::setFocusedDisplay(). Các ứng dụng tập trung cũng được cập nhật riêng biệt trong InputManagerService thông qua NativeInputManager::setFocusedApplication().

Trong WindowManager, các cửa sổ được lấy tiêu điểm cũng được theo dõi riêng. Xem DisplayContent#mCurrentFocusDisplayContent#mFocusedApp và các trường hợp sử dụng tương ứng. Tiêu điểm liên quan đã chuyển các phương pháp theo dõi và cập nhật WindowManagerService thành DisplayContent.