Chiếu nội dung nghe nhìn

android.media.projection API ra mắt trong Android 5 (API cấp 21) cho phép bạn thu thập nội dung của màn hình thiết bị dưới dạng luồng nội dung nghe nhìn mà bạn có thể phát lại, ghi hoặc truyền đến các thiết bị khác, chẳng hạn như TV.

Android 14 (API cấp 34) ra mắt tính năng chia sẻ màn hình ứng dụng, cho phép người dùng chia sẻ một cửa sổ ứng dụng thay vì toàn bộ màn hình thiết bị bất kể chế độ cửa sổ. Tính năng chia sẻ màn hình ứng dụng không bao gồm thanh trạng thái, thanh điều hướng các thông báo và các phần tử khác trên giao diện người dùng hệ thống từ màn hình dùng chung, thậm chí còn khi tính năng chia sẻ màn hình ứng dụng được dùng để chụp một ứng dụng ở chế độ toàn màn hình. Chỉ nội dung của ứng dụng đã chọn mới được chia sẻ.

Tính năng chia sẻ màn hình ứng dụng đảm bảo quyền riêng tư của người dùng, tăng năng suất của người dùng và tăng cường khả năng đa nhiệm bằng cách cho phép người dùng chạy nhiều ứng dụng nhưng hạn chế nội dung chia sẻ với một ứng dụng duy nhất.

Ba cách hiển thị

Tính năng chiếu nội dung đa phương tiện chụp lại nội dung của màn hình thiết bị hoặc cửa sổ ứng dụng và sau đó chiếu hình ảnh được chụp lên một màn hình ảo để kết xuất hình ảnh đó trên Surface.

Màn hình thiết bị thực tế chiếu lên màn hình ảo. Nội dung của màn hình ảo được ghi vào `Bề mặt` (Surface) do ứng dụng cung cấp.
Hình 1. Màn hình thiết bị thực hoặc cửa sổ ứng dụng chiếu lên màn hình ảo. Màn hình ảo được ghi vào ứng dụng do ứng dụng cung cấp Surface.

Ứng dụng cung cấp Surface thông qua một giao diện MediaRecorder, SurfaceTexture hoặc ImageReader, tiêu thụ nội dung của màn hình đã chụp và cho phép bạn quản lý hình ảnh được kết xuất trên Surface theo thời gian thực. Bạn có thể lưu hình ảnh dưới dạng bản ghi hoặc truyền chúng sang TV hoặc thiết bị khác.

Màn hình thực

Bắt đầu phiên chiếu nội dung đa phương tiện bằng cách lấy mã thông báo cấp cho ứng dụng của bạn khả năng chụp nội dung của màn hình thiết bị hoặc cửa sổ ứng dụng. Mã thông báo được biểu thị bằng một bản sao của MediaProjection .

Sử dụng phương thức getMediaProjection() của Dịch vụ hệ thống của MediaProjectionManager để tạo một thực thể MediaProjection khi bạn bắt đầu một hoạt động mới. Bắt đầu hoạt động bằng ý định trong Phương thức createScreenCaptureIntent() để chỉ định một màn hình thao tác chụp:

Kotlin

val mediaProjectionManager = getSystemService(MediaProjectionManager::class.java)
var mediaProjection : MediaProjection

val startMediaProjection = registerForActivityResult(
    StartActivityForResult()
) { result ->
    if (result.resultCode == RESULT_OK) {
        mediaProjection = mediaProjectionManager
            .getMediaProjection(result.resultCode, result.data!!)
    }
}

startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent())

Java

final MediaProjectionManager mediaProjectionManager =
    getSystemService(MediaProjectionManager.class);
final MediaProjection[] mediaProjection = new MediaProjection[1];

ActivityResultLauncher<Intent> startMediaProjection = registerForActivityResult(
    new StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Activity.RESULT_OK) {
            mediaProjection[0] = mediaProjectionManager
                .getMediaProjection(result.getResultCode(), result.getData());
        }
    }
);

startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());

Màn hình ảo

Tâm điểm của tính năng chiếu nội dung đa phương tiện là màn hình ảo mà bạn tạo bằng cách gọi createVirtualDisplay() cho thực thể MediaProjection:

Kotlin

virtualDisplay = mediaProjection.createVirtualDisplay(
                     "ScreenCapture",
                     width,
                     height,
                     screenDensity,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                     surface,
                     null, null)

Java

virtualDisplay = mediaProjection.createVirtualDisplay(
                     "ScreenCapture",
                     width,
                     height,
                     screenDensity,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                     surface,
                     null, null);

Các tham số widthheight chỉ định các kích thước của ảo màn hình. Để nhận giá trị cho chiều rộng và chiều cao, hãy sử dụng Ra mắt các API WindowMetrics trong Android 11 (API cấp 30). (Để biết chi tiết, hãy xem Kích thước chiếu nội dung đa phương tiện.)

Bề mặt

Xác định kích thước bề mặt chiếu nội dung đa phương tiện để tạo ra đầu ra ở mức thích hợp độ phân giải. Tạo bề mặt lớn (độ phân giải thấp) để truyền màn hình sang TV hoặc và màn hình máy tính nhỏ (độ phân giải cao) để ghi màn hình thiết bị.

Kể từ Android 12L (API cấp 32), khi hiển thị nội dung được ghi trên nền tảng, hệ thống điều chỉnh tỷ lệ nội dung một cách đồng nhất, duy trì tỷ lệ khung hình, để cả hai kích thước nội dung (chiều rộng và chiều cao) bằng hoặc nhỏ hơn so với kích thước tương ứng của bề mặt. Sau đó, nội dung đã ghi sẽ nằm ở giữa bề mặt.

Cách tiếp cận mở rộng quy mô của Android 12L cải thiện việc truyền màn hình đến TV và các màn hình lớn khác bằng cách tối đa hoá kích thước của hình ảnh bề mặt trong khi vẫn đảm bảo tỷ lệ khung hình phù hợp.

Quyền cho dịch vụ trên nền trước

Nếu ứng dụng của bạn nhắm đến Android 14 trở lên, thì tệp kê khai ứng dụng phải chứa một khai báo quyền cho Loại dịch vụ trên nền trước mediaProjection:

<manifest ...>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
    <application ...>
        <service
            android:name=".MyMediaProjectionService"
            android:foregroundServiceType="mediaProjection"
            android:exported="false">
        </service>
    </application>
</manifest>

Bắt đầu dịch vụ chiếu nội dung đa phương tiện bằng lệnh gọi đến startForeground().

Nếu bạn không chỉ định kiểu dịch vụ trên nền trước trong lệnh gọi, thì kiểu mặc định thành một số nguyên bitwise của các kiểu dịch vụ trên nền trước được xác định trong tệp kê khai. Nếu tệp kê khai không chỉ định bất kỳ loại dịch vụ nào, hệ thống sẽ gửi ra MissingForegroundServiceTypeException.

Ứng dụng của bạn phải yêu cầu người dùng đồng ý trước mỗi phiên chiếu nội dung đa phương tiện. Đáp là một lệnh gọi đến createVirtualDisplay(). Mã thông báo MediaProjection chỉ được sử dụng một lần để thực hiện cuộc gọi.

Trên Android 14 trở lên, phương thức createVirtualDisplay() sẽ gửi một SecurityException nếu ứng dụng thực hiện một trong những việc sau:

  • Truyền một thực thể Intent được trả về từ createScreenCaptureIntent() cho getMediaProjection() nhiều lần
  • Gọi createVirtualDisplay() nhiều lần trên cùng một MediaProjection thực thể

Kích thước chiếu nội dung đa phương tiện

Phép chiếu nội dung đa phương tiện có thể chụp toàn bộ màn hình thiết bị hoặc cửa sổ ứng dụng bất kể chế độ kết xuất cửa sổ hiện tại.

Kích thước ban đầu

Với tính năng chiếu nội dung nghe nhìn toàn màn hình, ứng dụng của bạn phải xác định kích thước của phần tử màn hình thiết bị. Trong tính năng chia sẻ màn hình ứng dụng, ứng dụng của bạn sẽ không thể xác định kích thước của màn hình được chụp cho đến khi người dùng chọn khu vực chụp. Vì vậy, kích thước ban đầu của mọi phép chiếu nội dung đa phương tiện là kích thước của màn hình thiết bị.

Sử dụng nền tảng WindowManager Phương thức getMaximumWindowMetrics() để trả về một WindowMetrics cho thuộc tính màn hình thiết bị ngay cả khi ứng dụng lưu trữ tính năng chiếu nội dung đa phương tiện ở chế độ nhiều cửa sổ chỉ chiếm một phần màn hình.

Để tương thích xuống API cấp 14, hãy sử dụng WindowMetricsCalculator computeMaximumWindowMetrics() từ thư viện Jetpack WindowManager.

Gọi phương thức WindowMetrics getBounds() để lấy chiều rộng và chiều cao của màn hình thiết bị.

Thay đổi về kích thước

Kích thước của hình chiếu nội dung đa phương tiện có thể thay đổi khi thiết bị được xoay hoặc người dùng chọn một cửa sổ ứng dụng làm khu vực chụp trong tính năng chia sẻ màn hình ứng dụng. Phép chiếu nội dung đa phương tiện có thể ở dạng hòm thư nếu nội dung được chụp là kích thước khác với chỉ số cửa sổ tối đa thu được khi nội dung nghe nhìn phép chiếu đã được thiết lập.

Để đảm bảo phép chiếu nội dung đa phương tiện căn chỉnh chính xác với kích thước của ảnh được chụp nội dung cho bất kỳ vùng nào được chụp và trên các xoay thiết bị, hãy sử dụng Lệnh gọi lại onCapturedContentResize() để đổi kích thước ảnh chụp. (Để biết thêm thông tin hãy xem phần Tuỳ chỉnh bên dưới).

Tuỳ chỉnh

Ứng dụng của bạn có thể tuỳ chỉnh trải nghiệm người dùng với tính năng chiếu nội dung đa phương tiện bằng các cách sau Các API MediaProjection.Callback:

  • onCapturedContentVisibilityChanged(): Cho phép ứng dụng lưu trữ (ứng dụng đã bắt đầu phép chiếu nội dung đa phương tiện) hiển thị hoặc ẩn nội dung được chia sẻ.

    Hãy sử dụng lệnh gọi lại này để tuỳ chỉnh giao diện người dùng của ứng dụng dựa trên việc hiển thị cho người dùng. Ví dụ: nếu ứng dụng của bạn hiển thị với và hiển thị nội dung được chụp trong giao diện người dùng của ứng dụng, đồng thời ứng dụng được chụp lại cũng hiển thị với người dùng (như được biểu thị thông qua ), người dùng sẽ thấy cùng một nội dung hai lần. Sử dụng lệnh gọi lại để cập nhật giao diện người dùng của ứng dụng để ẩn nội dung đã ghi và giải phóng không gian bố cục trong cho nội dung khác.

  • onCapturedContentResize(): Cho phép ứng dụng lưu trữ thay đổi kích thước của chế độ chiếu nội dung đa phương tiện trên máy ảo chiếu màn hình và nội dung nghe nhìn Surface dựa trên kích thước của ảnh chụp khu vực hiển thị.

    Được kích hoạt bất cứ khi nào nội dung được ghi lại – một cửa sổ ứng dụng hoặc toàn bộ màn hình thiết bị — thay đổi kích thước (do xoay thiết bị hoặc ảnh chụp ứng dụng chuyển sang chế độ cửa sổ khác). Sử dụng API này để đổi kích thước cả hai màn hình và bề mặt ảo để đảm bảo tỷ lệ khung hình khớp với ảnh chụp và ảnh chụp không ở dạng hòm thư.

Khôi phục tài nguyên

Ứng dụng của bạn phải đăng ký MediaProjection onStop() lệnh gọi lại để biết thời điểm phiên chiếu nội dung đa phương tiện bị dừng và kết thúc không hợp lệ. Khi phiên bị dừng, ứng dụng sẽ giải phóng các tài nguyên nó giữ, chẳng hạn như màn hình ảo và bề mặt chiếu. A đã dừng phiên chiếu nội dung đa phương tiện không thể tạo màn hình ảo mới được nữa, ngay cả khi ứng dụng của bạn trước đây chưa tạo màn hình ảo cho phép chiếu nội dung đa phương tiện đó.

Lệnh gọi lại được gọi khi quá trình chiếu nội dung đa phương tiện kết thúc, do người dùng dừng phiên theo cách thủ công hoặc do hệ thống dừng phiên lý do nào đó.

Nếu ứng dụng của bạn không đăng ký lệnh gọi lại, thì mọi lệnh gọi đến createVirtualDisplay() ném IllegalStateException.

Ngừng

Android 14 trở lên cho phép chia sẻ màn hình ứng dụng theo mặc định. Mỗi nội dung nghe nhìn Phiên chiếu cho phép người dùng lựa chọn chia sẻ cửa sổ ứng dụng hoặc toàn bộ màn hình.

Ứng dụng của bạn có thể chọn không chia sẻ màn hình ứng dụng bằng cách gọi Phương thức createScreenCaptureIntent(MediaProjectionConfig) có đối số MediaProjectionConfig được trả về từ lệnh gọi đến createConfigForDefaultDisplay().

Lệnh gọi đến createScreenCaptureIntent(MediaProjectionConfig) bằng Đối số MediaProjectionConfig được trả về từ lệnh gọi tới createConfigForUserChoice() giống nhau làm hành vi mặc định, tức là lệnh gọi đến createScreenCaptureIntent().

Ứng dụng có thể thay đổi kích thước

Kích thước ứng dụng chiếu nội dung đa phương tiện phải luôn có thể đổi kích thước (resizeableActivity="true"). Có thể thay đổi kích thước các ứng dụng hỗ trợ thay đổi cấu hình thiết bị và chế độ nhiều cửa sổ (xem Hỗ trợ nhiều cửa sổ).

Nếu không thể đổi kích thước, ứng dụng phải truy vấn ranh giới hiển thị qua một cửa sổ ngữ cảnh và sử dụng getMaximumWindowMetrics() để truy xuất WindowMetrics của khu vực hiển thị tối đa có sẵn cho ứng dụng :

Kotlin

val windowContext = context.createWindowContext(context.display!!,
      WindowManager.LayoutParams.TYPE_APPLICATION, null)
val projectionMetrics = windowContext.getSystemService(WindowManager::class.java)
      .maximumWindowMetrics

Java

Context windowContext = context.createWindowContext(context.getDisplay(),
      WindowManager.LayoutParams.TYPE_APPLICATION, null);
WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class)
      .getMaximumWindowMetrics();

Tài nguyên khác

Để biết thêm thông tin về phép chiếu nội dung đa phương tiện, vui lòng xem nội dung Quay video và phát lại âm thanh.