Android 14 (API cấp 34) ra mắt một số điểm cải tiến cho API hình trong hình (PiP) để hỗ trợ đa nhiệm. Mặc dù tính năng hỗ trợ PiP được ra mắt trong Android 8.0 (cấp độ API 26), nhưng tính năng này không được hỗ trợ rộng rãi trên Android TV và hoàn toàn không được hỗ trợ trên Google TV trước Android 13. Tính năng đa nhiệm cho TV sử dụng chế độ PiP để cho phép hai ứng dụng riêng biệt cùng tồn tại trên màn hình: một ứng dụng chạy ở chế độ toàn màn hình, còn ứng dụng thứ hai chạy ở chế độ PiP. Có các yêu cầu khác nhau đối với ứng dụng chạy ở một trong hai chế độ này.
Hành vi mặc định là ứng dụng PiP phủ lên ứng dụng toàn màn hình. Điều này gần giống với hành vi hình trong hình chuẩn của Android.
Lưu ý rằng khi tích hợp tính năng đa nhiệm, ứng dụng của bạn phải khai báo loại hình sử dụng theo nguyên tắc về chất lượng của ứng dụng truyền hình.
Chạy ứng dụng ở chế độ PiP
Đối với các thiết bị TV chạy Android 14 (API cấp 34) trở lên, hãy chạy ứng dụng ở chế độ PiP bằng cách gọi enterPictureInPictureMode(). Các thiết bị TV chạy phiên bản Android cũ hơn không hỗ trợ chế độ PiP.
Dưới đây là ví dụ về cách triển khai logic của một nút để chuyển sang chế độ Hình trong hình:
Kotlin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) pictureInPictureButton.visibility = if (requireActivity().packageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { pictureInPictureButton.setOnClickListener { val aspectRatio = Rational(view.width, view.height) val params = PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .build() val result = requireActivity().enterPictureInPictureMode(params) } View.VISIBLE } else { View.GONE } }
Java
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (requireActivity().getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
pictureInPictureButton.setVisibility(View.VISIBLE);
pictureInPictureButton.setOnClickListener(v -> {
Rational aspectRatio = new Rational(view.getWidth(), view.getHeight());
PictureInPictureParams params = new PictureInPictureParams.Builder()
.setAspectRatio(aspectRatio)
.setTitle("My Streaming App")
.setSubtitle("My On-Demand Content")
.build();
Boolean result = requireActivity().enterPictureInPictureMode(params);
});
} else {
pictureInPictureButton.setVisibility(View.GONE);
}
}
Thao tác chỉ được thêm nếu thiết bị có tính năng hệ thống FEATURE_PICTURE_IN_PICTURE. Ngoài ra, khi hành động được kích hoạt, tỷ lệ khung hình của chế độ PiP sẽ được đặt cho khớp với tỷ lệ khung hình của video đang phát.
Hãy nhớ thêm tiêu đề và phụ đề để cung cấp cho người dùng thông tin về mục đích sử dụng chung của PIP này.
Cùng tồn tại với các ứng dụng chạy ở chế độ PiP
Khi chạy dưới dạng ứng dụng toàn màn hình, ứng dụng của bạn có thể cần phải điều chỉnh cho phù hợp với các ứng dụng khác đang chạy ở chế độ PiP.
API Keep-clear
Trong một số trường hợp, ứng dụng PiP có thể phủ lên các thành phần giao diện người dùng quan trọng trong ứng dụng toàn màn hình. Để giảm thiểu vấn đề này, có các API giữ rõ ràng mà ứng dụng có thể dùng để xác định các thành phần giao diện người dùng quan trọng không nên bị phủ lên. Hệ thống sẽ cố gắng đáp ứng các yêu cầu để tránh che khuất các thành phần này bằng cách định vị lại cửa sổ PiP.
Để chỉ định rằng một khung hiển thị không được phủ lên, hãy sử dụng preferKeepClear trong bố cục XML của bạn như trong ví dụ sau:
<TextView
android:id="@+id/important_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:preferKeepClear="true"
android:text="@string/app_name"/>
Bạn cũng có thể thực hiện việc này theo phương thức lập trình bằng cách sử dụng setPreferKeepClear():
Kotlin
private lateinit var binding: MyLayoutBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = MyLayoutBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.importantText.isPreferKeepClear = true
}
Java
private MyLayoutBinding binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = MyLayoutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.importantText.setPreferKeepClear(true);
}
Đôi khi, bạn không cần phải giữ cho toàn bộ View trống, mà chỉ cần một phần của nó. Bạn có thể sử dụng setPreferKeepClearRects() để chỉ định các vùng của View không được phủ lên. Giao diện người dùng không sử dụng View theo cách gốc (chẳng hạn như Flutter, Jetpack Compose và WebView) có thể có các tiểu mục cần giữ cho vùng không bị che khuất. Bạn có thể sử dụng API này cho những trường hợp đó.
Kiểu sử dụng
Ứng dụng của bạn phải khai báo thuộc tính giá trị siêu dữ liệu của com.google.android.tv.pip.category tương ứng với (các) loại hình sử dụng chính cho chế độ hình trong hình. Mọi <activity> đã đặt android:supportsPictureInPicture="true" phải khai báo thuộc tính này bằng một giá trị có liên quan trong bảng sau.
Các loại hình sử dụng không thuộc bất kỳ danh mục nào trong số này, đặc biệt là mọi hoạt động phát nội dung nghe nhìn, đều không được phép ở chế độ hình trong hình trên TV.
| Giá trị | Mô tả |
|---|---|
"communication" |
Các trường hợp sử dụng liên lạc, chẳng hạn như cuộc gọi video hoặc cuộc gọi thoại. |
"smartHome" |
Các công cụ tích hợp nhà thông minh, chẳng hạn như chuông cửa hoặc thiết bị giám sát trẻ em được kết nối. |
"health" |
Trường hợp sử dụng liên quan đến sức khoẻ, chẳng hạn như theo dõi hoạt động thể dục hoặc theo dõi sức khoẻ. |
"ticker" |
Các trường hợp sử dụng biểu ngữ, chẳng hạn như tỷ số thể thao trực tiếp hoặc biểu ngữ tin tức và cổ phiếu. |
Nhiều giá trị được phân tách bằng dấu gạch đứng (|). Ví dụ:
<meta-data android:name="com.google.android.tv.pip.category" android:value="smartHome|health" />