Proyeksi media

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

Android 14 (API level 34) memperkenalkan fitur berbagi layar aplikasi, yang memungkinkan pengguna membagikan satu jendela aplikasi, bukan seluruh layar perangkat, terlepas dari mode jendela. Berbagi layar aplikasi mengecualikan status bar, menu navigasi, notifikasi, dan elemen UI sistem lainnya dari tampilan bersama—bahkan saat berbagi layar aplikasi digunakan untuk merekam aplikasi dalam layar penuh. Hanya konten aplikasi yang dipilih yang dibagikan.

Berbagi layar aplikasi memastikan privasi pengguna, meningkatkan produktivitas pengguna, dan meningkatkan multitasking dengan memungkinkan pengguna menjalankan beberapa aplikasi, tetapi membatasi berbagi konten hanya ke satu aplikasi.

Tiga representasi tampilan

Proyeksi media menangkap konten layar perangkat atau jendela aplikasi, lalu memproyeksikan gambar yang diambil ke layar virtual yang merender gambar pada Surface.

Tampilan perangkat sebenarnya yang diproyeksikan ke tampilan virtual. Konten
              tampilan virtual yang ditulis ke `Surface` yang disediakan aplikasi.
Gambar 1. Layar perangkat atau jendela aplikasi sebenarnya yang diproyeksikan ke layar virtual. Tampilan virtual yang ditulis ke Surface yang disediakan aplikasi.

Aplikasi menyediakan Surface melalui MediaRecorder, SurfaceTexture, atau ImageReader, yang menggunakan konten tampilan yang diambil dan memungkinkan Anda mengelola gambar yang dirender di Surface secara real time. Anda dapat menyimpan gambar sebagai rekaman atau mentransmisikannya ke TV atau perangkat lainnya.

Tampilan nyata

Mulai sesi proyeksi media dengan mendapatkan token yang memberi aplikasi Anda kemampuan untuk menangkap konten tampilan perangkat atau jendela aplikasi. Token tersebut diwakili oleh instance class MediaProjection.

Gunakan metode getMediaProjection() dari layanan sistem MediaProjectionManager untuk membuat instance MediaProjection saat Anda memulai aktivitas baru. Mulai aktivitas dengan intent dari metode createScreenCaptureIntent() untuk menentukan operasi pengambilan screenshot:

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 startMediaProjection = registerForActivityResult( new StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { mediaProjection[0] = mediaProjectionManager .getMediaProjection(result.getResultCode(), result.getData()); } } );
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());

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 dimensi tampilan virtual. Untuk mendapatkan nilai lebar dan tinggi, gunakan WindowMetrics API yang diperkenalkan di Android 11 (level API 30). (Untuk mengetahui detailnya, lihat bagian Ukuran Proyeksi media.)

Platform

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

Mulai Android 12L (API level 32), saat merender konten yang diambil di platform, sistem menskalakan konten secara seragam, mempertahankan rasio aspek, sehingga kedua dimensi konten (lebar dan tinggi) sama dengan atau kurang dari dimensi platform yang sesuai. Konten yang diambil kemudian diposisikan di tengah platform.

Pendekatan penskalaan Android 12L meningkatkan transmisi layar ke televisi dan layar besar lainnya dengan memaksimalkan ukuran gambar platform sekaligus memastikan rasio aspek yang tepat.

Izin layanan latar depan

Jika aplikasi Anda menargetkan Android 14 atau yang lebih tinggi, manifes aplikasi harus menyertakan deklarasi izin untuk jenis layanan latar depan 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>

Mulai layanan proyeksi media dengan panggilan ke startForeground().

Jika Anda tidak menentukan jenis layanan latar depan dalam panggilan, jenis tersebut akan ditetapkan secara default ke bilangan bulat bitwise dari jenis layanan latar depan yang ditentukan dalam manifes. Jika manifes tidak menentukan jenis layanan apa pun, sistem akan menampilkan MissingForegroundServiceTypeException.

Aplikasi Anda harus meminta izin pengguna sebelum setiap sesi proyeksi media. Sesi adalah satu panggilan ke createVirtualDisplay(). Token MediaProjection hanya boleh digunakan satu kali untuk melakukan panggilan.

Di Android 14 atau yang lebih tinggi, metode createVirtualDisplay() akan menampilkan SecurityException jika aplikasi Anda melakukan salah satu hal berikut:

  • Meneruskan instance Intent yang ditampilkan dari createScreenCaptureIntent() ke getMediaProjection() lebih dari sekali
  • Memanggil createVirtualDisplay() lebih dari sekali pada instance MediaProjection yang sama

Ukuran proyeksi media

Proyeksi media dapat merekam seluruh tampilan perangkat atau jendela aplikasi terlepas dari mode jendela.

Ukuran awal

Dengan proyeksi media layar penuh, aplikasi Anda harus menentukan ukuran layar perangkat. Dalam berbagi layar aplikasi, aplikasi Anda tidak akan dapat menentukan ukuran tampilan yang diambil hingga pengguna memilih wilayah pengambilan. Jadi, ukuran awal proyeksi media adalah ukuran layar perangkat.

Gunakan metode WindowManager getMaximumWindowMetrics() platform untuk menampilkan objek WindowMetrics untuk layar perangkat meskipun aplikasi host proyeksi media dalam mode multi-aplikasi, yang hanya menempati sebagian layar.

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

Panggil metode WindowMetrics getBounds() untuk mendapatkan lebar dan tinggi layar perangkat.

Perubahan ukuran

Ukuran proyeksi media dapat berubah saat perangkat diputar atau pengguna memilih jendela aplikasi sebagai wilayah pengambilan dalam berbagi layar aplikasi. Proyeksi media mungkin memiliki tampilan lebar jika konten yang diambil memiliki ukuran yang berbeda dengan metrik jendela maksimum yang diperoleh saat proyeksi media disiapkan.

Untuk memastikan proyeksi media selaras dengan ukuran konten yang diambil untuk setiap wilayah yang diambil dan di seluruh rotasi perangkat, gunakan callback onCapturedContentResize() untuk mengubah ukuran pengambilan. (Untuk informasi selengkapnya, lihat bagian Penyesuaian, yang akan dijelaskan berikutnya).

Penyesuaian

Aplikasi Anda dapat menyesuaikan pengalaman pengguna proyeksi media dengan MediaProjection.Callback API berikut:

  • onCapturedContentVisibilityChanged(): Memungkinkan aplikasi host (aplikasi yang memulai proyeksi media) untuk menampilkan atau menyembunyikan konten yang dibagikan.

    Gunakan callback ini untuk menyesuaikan UI aplikasi berdasarkan apakah wilayah yang diambil dapat dilihat oleh pengguna. Misalnya, jika aplikasi Anda terlihat oleh pengguna dan menampilkan konten yang diambil dalam UI aplikasi, dan aplikasi yang diambil juga terlihat oleh pengguna (seperti yang ditunjukkan melalui callback ini), pengguna akan melihat konten yang sama dua kali. Gunakan callback untuk mengupdate UI aplikasi Anda guna menyembunyikan konten yang diambil dan mengosongkan ruang tata letak di aplikasi Anda untuk konten lain.

  • onCapturedContentResize(): Memungkinkan aplikasi host mengubah ukuran projector media pada tampilan virtual dan proyeksi media Surface berdasarkan ukuran wilayah tampilan yang diambil.

    Dipicu setiap kali konten yang diambil—satu jendela aplikasi atau tampilan perangkat penuh—mengubah ukuran (karena rotasi perangkat atau aplikasi yang diambil memasuki mode jendela yang berbeda). Gunakan API ini untuk mengubah ukuran tampilan virtual dan platform untuk memastikan rasio aspek cocok dengan konten yang diambil dan pengambilan tidak dalam format letterbox.

Pemulihan resource

Aplikasi Anda harus mendaftarkan callback MediaProjection onStop() untuk diberi tahu saat sesi proyeksi media dihentikan dan menjadi tidak valid. Saat sesi dihentikan, aplikasi Anda harus melepaskan resource yang disimpannya, seperti tampilan virtual dan platform proyeksi. Sesi proyeksi media yang dihentikan tidak dapat lagi membuat tampilan virtual baru, meskipun aplikasi Anda sebelumnya belum membuat tampilan virtual untuk proyeksi media tersebut.

Sistem memanggil callback saat proyeksi media dihentikan. Penghentian ini dapat terjadi karena beberapa alasan, seperti:

  • pengguna menghentikan sesi menggunakan UI aplikasi atau chip status projector media sistem
  • layar sedang dikunci
  • sesi proyeksi media lain dimulai
  • proses aplikasi dihentikan

Jika aplikasi Anda tidak mendaftarkan callback, setiap panggilan ke createVirtualDisplay() akan menampilkan IllegalStateException.

Nonaktifkan

Android 14 atau yang lebih tinggi mengaktifkan berbagi layar aplikasi secara default. Setiap sesi proyeksi media memberi pengguna opsi untuk membagikan jendela aplikasi atau seluruh layar.

Aplikasi Anda dapat memilih untuk tidak berbagi layar aplikasi dengan memanggil metode createScreenCaptureIntent(MediaProjectionConfig) dengan argumen MediaProjectionConfig yang ditampilkan dari panggilan ke createConfigForDefaultDisplay().

Panggilan ke createScreenCaptureIntent(MediaProjectionConfig) dengan argumen MediaProjectionConfig yang ditampilkan dari panggilan ke createConfigForUserChoice() sama dengan perilaku default, yaitu, panggilan ke createScreenCaptureIntent().

Aplikasi yang ukurannya dapat disesuaikan

Selalu buat aplikasi proyeksi media Anda dapat diubah ukurannya (resizeableActivity="true"). Aplikasi yang dapat diubah ukurannya mendukung perubahan konfigurasi perangkat dan mode multi-aplikasi (lihat Dukungan multi-aplikasi).

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

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

Chip status bar dan berhenti otomatis

Eksploitasi proyeksi layar mengekspos data pengguna pribadi seperti informasi keuangan karena pengguna tidak menyadari bahwa layar perangkat mereka sedang dibagikan.

Android 15 (API level 35) dan yang lebih tinggi menampilkan chip status bar yang besar dan jelas untuk memberi tahu pengguna tentang proyeksi layar yang sedang berlangsung. Pengguna dapat mengetuk chip untuk menghentikan layar mereka agar tidak dibagikan, ditayangkan, atau direkam. Selain itu, proyeksi layar akan otomatis berhenti saat layar perangkat dikunci.

Gambar 2. Chip status bar untuk berbagi layar, transmisi, dan perekaman.

Uji ketersediaan chip status bar proyeksi media dengan memulai berbagi layar, transmisi, atau perekaman. Chip akan muncul di status bar.

Untuk memastikan aplikasi Anda merilis resource dan memperbarui UI-nya saat proyeksi layar dihentikan oleh interaksi pengguna dengan chip status bar atau dengan aktivasi layar kunci, lakukan tindakan berikut:

  • Buat instance MediaProjection.Callback.

  • Implementasikan metode callback onStop(). Metode ini dipanggil saat proyeksi layar berhenti. Lepaskan resource apa pun yang disimpan aplikasi Anda dan update UI aplikasi sesuai kebutuhan.

Untuk menguji callback, ketuk chip status bar atau kunci layar perangkat untuk menghentikan proyeksi layar. Pastikan metode onStop() dipanggil dan aplikasi Anda merespons seperti yang diinginkan.

Referensi lainnya

Untuk informasi proyeksi media selengkapnya, lihat Merekam pemutaran video dan audio.