Chiếu nội dung nghe nhìn

API android.media.projection được giới thiệu trong Android 5 (API cấp 21) cho phép bạn chụp lại nội dung của màn hình thiết bị dưới dạng luồng nội dung đa phương tiện bạn có thể phát lại, quay hoặc truyền sang các thiết bị khác 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ổ là gì. Tính năng chia sẻ màn hình ứng dụng sẽ loại trừ thanh trạng thái, thanh điều hướng, thông báo và các thành phần khác trên giao diện người dùng hệ thống khỏi màn hình dùng chung, ngay cả khi tính năng chia sẻ màn hình ứng dụng được dùng để chụp ứ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ế việc chia sẻ nội dung chỉ trên một ứng dụng duy nhất.

Ba phần đại diện cho màn hình

Tính năng chiếu nội dung đa phương tiện sẽ chụp lại nội dung của màn hình thiết bị hoặc cửa sổ ứng dụng, sau đó chiếu hình ảnh đã chụp lên 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 Surface do ứng dụng cung cấp.

Ứng dụng cung cấp Surface thông qua MediaRecorder, SurfaceTexture hoặc ImageReader, giúp sử dụng nội dung của màn hình đã chụp và cho phép bạn quản lý hình ảnh 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 vào 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 giúp ứng dụng của bạn có thể chụp lại nội dung trên 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 thực thể của lớp MediaProjection.

Sử dụng phương thức getMediaProjection() của dịch vụ hệ thống MediaProjectionManager để tạo 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 thao tác chụp màn hình:

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 kích thước của màn hình ảo. Để lấy giá trị cho chiều rộng và chiều cao, hãy sử dụng các API WindowMetrics được giới thiệu trong Android 11 (API cấp 30). (Để biết thông tin chi tiết, vui lòng xem phần Kích thước chiếu nội dung đa phương tiện.)

Bề mặt

Định kích thước bề mặt chiếu nội dung đa phương tiện để tạo đầu ra ở độ phân giải thích hợp. Kích thước bề mặt lớn (độ phân giải thấp) để truyền sang TV hoặc màn hình máy tính và kích thước 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 đã ghi trên nền tảng, hệ thống sẽ đ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 của nội dung (chiều rộng và chiều cao) bằng hoặc nhỏ hơn kích thước tương ứng của nền tảng. Sau đó, nội dung đã chụp sẽ được căn giữa trên nền tảng.

Phương pháp điều chỉnh theo tỷ lệ của Android 12L giúp cải thiện tính năng 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 bao gồm nội dung 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 này sẽ mặc định thành 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 loại dịch vụ nào, hệ thống sẽ gửi 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. Phiên là một lệnh gọi duy nhất đến createVirtualDisplay(). Bạn chỉ được sử dụng mã thông báo MediaProjection một lần để thực hiện lệnh gọi.

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

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

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ế độ cửa sổ.

Kích thước ban đầu

Khi 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 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ị.

Dùng phương thức nền tảng WindowManager getMaximumWindowMetrics() để trả về một WindowMetrics đối tượng cho màn hình thiết bị ngay cả khi phần ứng dụng lưu trữ tính năng chiếu nội dung đa phương tiện chỉ đang ở chế độ hiển thị.

Để tương thích xuống API cấp 14, hãy sử dụng phương thức 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 kích thước

Kích thước của phép chiếu nội dung đa phương tiện có thể thay đổi khi xoay thiết bị hoặc người dùng chọn một cửa sổ ứng dụng làm vùng 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 đã chụp có kích thước khác với chỉ số cửa sổ tối đa thu được khi thiết lập tính năng chiếu nội dung đa phương tiện.

Để đảm bảo phép chiếu nội dung đa phương tiện khớp chính xác với kích thước của nội dung được chụp cho mọi khu vực được chụp và giữa các chế độ 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 khi chiếu nội dung đa phương tiện bằng các API MediaProjection.Callback sau:

  • onCapturedContentVisibilityChanged(): Bật ứng dụng lưu trữ (ứng dụng đã bắt đầu tính năng chiếu nội dung đa phương tiện) để hiện 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 người dùng có nhìn thấy khu vực đã chụp hay không. Ví dụ: nếu người dùng nhìn thấy ứng dụng của bạn và đang cho thấy nội dung được ghi lại trong giao diện người dùng của ứng dụng, đồng thời ứng dụng được chụp cũng hiển thị cho người dùng (như được thể hiện trong lệnh gọi lại này), thì người dùng sẽ thấy cùng một nội dung hai lần. Hãy 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 nhằm ẩn nội dung đã chụp và giải phóng không gian bố cục trong ứng dụng cho nội dung khác.

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

    Được kích hoạt bất cứ khi nào nội dung được ghi (một cửa sổ ứng dụng hoặc màn hình toàn thiết bị) thay đổi kích thước (do việc xoay thiết bị hoặc ứng dụng đã chụp chuyển sang chế độ cửa sổ khác). Dùng API này để đổi kích thước cả màn hình và giao diện ảo nhằm đảm bảo tỷ lệ khung hình khớp với nội dung đã 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 nên đăng ký lệnh gọi lại MediaProjection onStop() để giải phóng các tài nguyên mà ứng dụng giữ, chẳng hạn như màn hình ảo và bề mặt chiếu.

Lệnh gọi lại được gọi khi tính năng chiếu nội dung đa phương tiện kết thúc hoặc khi người dùng không đồng ý để tiếp tục phiên chụp.

Nếu ứng dụng của bạn không đăng ký lệnh gọi lại và người dùng không đồng ý với phiên chiếu nội dung đa phương tiện, thì các lệnh gọi đến createVirtualDisplay() sẽ gửi IllegalStateException.

Ngừng

Theo mặc định, Android 14 trở lên sẽ bật tính năng chia sẻ màn hình ứng dụng. Mỗi phiên chiếu nội dung đa phương tiện cho phép người dùng 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 sử dụng tính năng chia sẻ màn hình ứng dụng bằng cách gọi phương thức createScreenCaptureIntent(MediaProjectionConfig) với đối số MediaProjectionConfig được trả về từ lệnh gọi đến createConfigForDefaultDisplay().

Lệnh gọi đến createScreenCaptureIntent(MediaProjectionConfig) có đối số MediaProjectionConfig được trả về từ lệnh gọi đến createConfigForUserChoice() cũng giống như 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

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

Nếu không thể đổi kích thước, ứng dụng của bạn phải truy vấn các ranh giới hiển thị từ ngữ cảnh cửa sổ 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.