Proyeksi media di perangkat layar besar

API proyeksi media yang diperkenalkan di Android 5 (API level 21) memungkinkan Anda menangkap konten tampilan perangkat sebagai streaming media yang dapat diputar, direkam, atau ditransmisikan ke perangkat lain seperti TV.

Proyeksi media mencakup tiga representasi layar perangkat:

Tampilan perangkat sebenarnya yang diproyeksikan ke tampilan virtual. Konten tampilan virtual yang ditulis ke `Surface` yang disediakan aplikasi.

Gambar 1. Tampilan perangkat sebenarnya yang diproyeksikan ke tampilan virtual. Konten tampilan virtual yang ditulis ke Surface yang disediakan aplikasi.

Proyeksi media menangkap konten tampilan perangkat lalu memproyeksikan gambar yang diambil ke tampilan virtual yang merender gambar pada Surface.

Aplikasi menyediakan Surface melalui SurfaceView atau ImageReader, yang memakai konten tampilan yang diambil. OnImageAvailableListener dari ImageReader memungkinkan Anda mengelola gambar yang dirender di Surface secara real time. Anda dapat menyimpan gambar sebagai rekaman atau mentransmisikannya ke TV atau perangkat lainnya.

MediaProjection

Mulai sesi proyeksi media dengan mendapatkan token yang memberi aplikasi kemampuan untuk menangkap konten tampilan, audio perangkat, atau keduanya. Token tersebut diwakili oleh instance class MediaProjection. Anda dapat membuat instance class ini saat memulai aktivitas baru.

Pendekatan lama

Untuk mendapatkan token proyeksi media menggunakan pendekatan lama, panggil startActivityForResult() dengan intent yang ditampilkan dari metode createScreenCaptureIntent() layanan sistem MediaProjectionManager:

Kotlin

startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(),
                       REQUEST_MEDIA_PROJECTION)

Java

startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(),
                       REQUEST_MEDIA_PROJECTION);

Panggilan tersebut menampilkan kotak dialog konfirmasi yang memberi tahu pengguna bahwa proyeksi media menangkap semua informasi yang ditampilkan, termasuk informasi sensitif atau informasi identitas pribadi.

Jika pengguna memberikan konfirmasi, startActivityForResult() akan meneruskan kode dan data hasil ke callback onActivityResult().

Selanjutnya, Anda dapat meneruskan data dan kode hasil ke metode getMediaProjection() dari MediaProjectionManager untuk membuat instance MediaProjection:

Kotlin

mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData)

Java

mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData);

Pendekatan yang direkomendasikan untuk mendapatkan token proyeksi media menggunakan API dari library Aktivitas Jetpack:

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());
    }
  }
);

Tampilan virtual

Inti proyeksi media adalah tampilan virtual, yang Anda buat dengan memanggil createVirtualDisplay() pada instance 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);

Parameter width dan height menentukan lebar dan tinggi tampilan virtual. Untuk mendapatkan nilai yang cocok dengan lebar dan tinggi proyeksi media, gunakan WindowMetrics API yang diperkenalkan di Android 11 (API level 30).

WindowMetrics

Proyeksi media menangkap seluruh tampilan, terlepas dari apakah aplikasi yang membuat proyeksi media berjalan dalam layar penuh atau dalam mode multi-aplikasi.

Metode yang benar untuk mendapatkan dimensi proyeksi media adalah WindowManager#getMaximumWindowMetrics(). Metode ini menampilkan objek WindowMetrics untuk tampilan penuh meskipun aplikasi proyeksi media berada dalam mode multi-aplikasi, yang hanya menempati sebagian tampilan.

Untuk kompatibilitas hingga API level 14, gunakan WindowMetricsCalculator#computeMaximumWindowMetrics() dari library Jetpack WindowManager.

Panggil WindowMetrics#getBounds() untuk mendapatkan lebar dan tinggi yang benar untuk tampilan virtual proyeksi media (lihat Tampilan virtual).

Selalu buat aplikasi proyeksi media Anda dapat diubah ukurannya. Aplikasi yang dapat diubah ukurannya mendukung perubahan konfigurasi ponsel dan mode multi-aplikasi (lihat Dukungan multi-aplikasi).

Jika aplikasi tidak dapat diubah ukurannya, aplikasi harus mengkueri batas tampilan dari konteks jendela dan mengambil WindowMetrics area tampilan maksimum yang tersedia untuk aplikasi menggunakan WindowManager#getMaximumWindowMetrics():

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();

Platform

Anda harus menentukan ukuran platform proyeksi media untuk menghasilkan output dalam resolusi yang diinginkan. Buat ukuran besar (resolusi rendah) untuk transmisi layar ke TV atau monitor komputer dan ukuran kecil (resolusi tinggi) untuk perekaman tampilan perangkat.

Mulai 12L (API level Sv2), saat sistem merender tampilan virtual pada platform, sistem akan menskalakan tampilan virtual agar sesuai dengan platform menggunakan proses yang serupa dengan opsi centerInside dari ImageView.

Pendekatan penskalaan baru ini meningkatkan transmisi layar ke televisi dan layar besar lainnya dengan memaksimalkan ukuran gambar platform sekaligus memastikan rasio lebar tinggi yang tepat.

Rekomendasi

Untuk mendapatkan hasil terbaik dengan proyeksi media, ikuti rekomendasi berikut:

  • Buat aplikasi agar dapat diubah ukurannya. Aplikasi yang dapat diubah ukurannya mendukung perubahan konfigurasi ponsel dan mode multi-aplikasi (lihat Dukungan multi-aplikasi). Di manifes aplikasi Anda, tetapkan resizeableActivity="true". Di Android 7.0 (API level 24), setelan ini adalah benar secara default.
  • Aktifkan aplikasi Anda untuk mendukung orientasi lanskap dan potret karena kedua orientasi tersebut umum digunakan di faktor bentuk ponsel, tablet, dan perangkat foldable.
  • Gunakan WindowManager#getMaximumWindowMetrics() untuk mendapatkan batasan proyeksi media. Untuk kompatibilitas hingga API level 14, gunakan Jetpack WindowManager. (Lihat bagian WindowMetrics.)
  • Jika aplikasi Anda tidak dapat diubah ukurannya, dapatkan batas proyeksi media dari konteks jendela. (Lihat bagian WindowMetrics.)

Referensi

Untuk mengetahui informasi selengkapnya, lihat Merekam pemutaran video dan audio.