Medya projeksiyonu

Android 5'te (API düzeyi 21) kullanıma sunulan android.media.projection API'leri, bir cihaz ekranının içeriğini oynatıp kaydedebileceğiniz veya TV gibi diğer cihazlara yayınlayabileceğiniz bir medya akışı olarak yakalamanıza olanak tanır.

Android 14 (API düzeyi 34), kullanıcıların pencere modundan bağımsız olarak cihaz ekranının tamamı yerine tek bir uygulama penceresini paylaşmasına olanak tanıyan uygulama ekranı paylaşımını kullanıma sunar. Uygulama ekran paylaşımı, bir uygulamayı tam ekranda yakalamak için kullanıldığında bile durum çubuğunu, gezinme çubuğunu, bildirimleri ve diğer sistem kullanıcı arayüzü öğelerini paylaşılan ekrandan hariç tutar. Yalnızca seçilen uygulamanın içeriği paylaşılır.

Uygulama ekranı paylaşımı, kullanıcı gizliliğini sağlar, kullanıcı üretkenliğini artırır ve kullanıcıların birden fazla uygulamayı çalıştırmasına olanak tanıyarak ancak içerik paylaşımını tek bir uygulamayla kısıtlayarak çoklu görev işlevini iyileştirir.

Üç görüntülü reklam temsili

Medya yansıtma, bir cihaz ekranının veya uygulama penceresinin içeriğini yakalar ve ardından yakalanan görüntüyü Surface üzerinde görüntüleyen sanal bir ekrana yansıtır.

Gerçek cihaz ekranı sanal ekrana yansıtılır. Uygulama tarafından sağlanan "Surface"a yazılan sanal ekranın içeriği.
Şekil 1. Gerçek cihaz ekranı veya uygulama penceresi sanal ekrana yansıtılır. Uygulama tarafından sağlanan Surface alanına yazılan sanal ekran.

Uygulama, Surface'yi MediaRecorder, SurfaceTexture veya ImageReader aracılığıyla sağlar. Bu API'ler, yakalanan ekranın içeriğini tüketir ve Surface'de oluşturulan resimleri gerçek zamanlı olarak yönetmenizi sağlar. Resimleri kayıt olarak kaydedebilir veya TV'ye ya da başka bir cihaza yayınlayabilirsiniz.

Gerçek ekran

Uygulamanıza cihaz ekranının veya uygulama penceresinin içeriğini yakalama olanağı tanıyan bir jeton alarak medya projeksiyon oturumu başlatın. Jeton, MediaProjection sınıfının bir örneğiyle temsil edilir.

Yeni bir etkinlik başlattığınızda MediaProjection örneği oluşturmak için MediaProjectionManager sistem hizmetinin getMediaProjection() yöntemini kullanın. Ekran yakalama işlemini belirtmek için etkinliği createScreenCaptureIntent() yönteminden bir intent ile başlatın:

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

Sanal ekran

Medya projeksiyonunun ana unsuru, MediaProjection örneğinde createVirtualDisplay() çağırarak oluşturduğunuz sanal ekrandır:

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

width ve height parametreleri, sanal ekranın boyutlarını belirtir. Genişlik ve yükseklik değerlerini almak için Android 11'de (API düzeyi 30) kullanıma sunulan WindowMetrics API'lerini kullanın. (Ayrıntılar için Medya projeksiyon boyutu bölümüne bakın.)

Yüzey

Medya projeksiyon yüzeyini, uygun çözünürlükte çıkış oluşturacak şekilde boyutlandırın. TV'lere veya bilgisayar monitörlerine ekran yayınlamak için yüzeyi büyük (düşük çözünürlüklü) ve cihaz ekranı kaydı için küçük (yüksek çözünürlüklü) yapın.

Android 12L (API düzeyi 32) itibarıyla, yakalanan içeriği yüzeyde oluştururken sistem, en boy oranını koruyarak içeriği eşit şekilde ölçeklendirir. Böylece içeriğin her iki boyutu da (genişlik ve yükseklik) yüzeyin ilgili boyutlarına eşit veya bu boyutlardan daha küçük olur. Daha sonra çekilen içerik yüzeyin ortasına yerleştirilir.

Android 12L ölçeklendirme yaklaşımı, yüzey resminin boyutunu en üst düzeye çıkarırken doğru en boy oranını sağlayarak televizyonlara ve diğer büyük ekranlara ekran yayınlamayı iyileştirir.

Ön plan hizmeti izni

Uygulamanız Android 14 veya sonraki sürümleri hedefliyorsa uygulama manifest dosyasında mediaProjection ön plan hizmet türü için izin beyanı bulunmalıdır:

<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>

startForeground() adresine çağrı yaparak medya projeksiyon hizmetini başlatın.

Çağrıda ön plan hizmet türünü belirtmezseniz tür, varsayılan olarak manifest'de tanımlanan ön plan hizmet türlerinin bitlik bir tam sayısı olur. Manifest'te herhangi bir hizmet türü belirtilmezse sistem MissingForegroundServiceTypeException hatası verir.

Uygulamanız her medya projeksiyon oturumundan önce kullanıcı izni istemelidir. Oturum, createVirtualDisplay()'a yapılan tek bir çağrıdır. Arama yapmak için MediaProjection jetonu yalnızca bir kez kullanılmalıdır.

Android 14 veya sonraki sürümlerde, uygulamanız aşağıdakilerden birini yapıyorsa createVirtualDisplay() yöntemi SecurityException hatası verir:

  • createScreenCaptureIntent()'dan getMediaProjection()'ye döndürülen bir Intent örneğini birden fazla kez iletir
  • Aynı MediaProjection örneğinde createVirtualDisplay() işlevini birden fazla kez çağırır.

Medya projeksiyonu boyutu

Medya yansıtma, pencere modundan bağımsız olarak cihaz ekranının tamamını veya bir uygulama penceresini yakalayabilir.

İlk boyut

Tam ekran medya yansıtma özelliğinde uygulamanız, cihaz ekranının boyutunu belirlemelidir. Uygulama içi ekran paylaşımında, kullanıcı yakalama bölgesini seçene kadar uygulamanız yakalanan ekranın boyutunu belirleyemez. Bu nedenle, herhangi bir medya projeksiyonunun ilk boyutu cihaz ekranının boyutudur.

Medya projeksiyonu ana uygulaması çoklu pencere modunda olsa ve ekranın yalnızca bir kısmını kaplasa bile cihaz ekranı için bir WindowMetrics nesnesi döndürmek üzere platform WindowManager getMaximumWindowMetrics() yöntemini kullanın.

API seviyesi 14'e kadar uyumluluk için Jetpack WindowManager kitaplığındaki WindowMetricsCalculator computeMaximumWindowMetrics() yöntemini kullanın.

Cihaz ekranının genişliğini ve yüksekliğini almak için WindowMetrics getBounds() yöntemini çağırın.

Boyut değişiklikleri

Cihaz döndürüldüğünde veya kullanıcı, uygulama ekranı paylaşımında yakalama bölgesi olarak bir uygulama penceresi seçtiğinde medya projeksiyonunun boyutu değişebilir. Kaydedilen içerik, medya projeksiyonu ayarlanırken elde edilen maksimum pencere metriklerinden farklı bir boyuttaysa medya projeksiyonu sinemaskoplu olabilir.

Medya projeksiyonunun, yakalanan tüm bölgelerde ve cihaz döndürmelerinde yakalanan içeriğin boyutuyla tam olarak hizalandığından emin olmak için yakalamayı yeniden boyutlandırmak üzere onCapturedContentResize() geri çağırma işlevini kullanın. (Daha fazla bilgi için aşağıdaki Özelleştirme bölümüne bakın.)

Özelleştirme

Uygulamanız, aşağıdaki MediaProjection.Callback API'leriyle medya projeksiyonu kullanıcı deneyimini özelleştirebilir:

  • onCapturedContentVisibilityChanged(): Ana uygulamanın (medya yansıtmayı başlatan uygulama) paylaşılan içeriği göstermesini veya gizlemesini sağlar.

    Uygulamanızın kullanıcı arayüzünü, yakalanan bölgenin kullanıcı tarafından görülebilmesine göre özelleştirmek için bu geri çağırma işlevini kullanın. Örneğin, uygulamanız kullanıcı tarafından görülebilir durumdaysa ve yakalanan içeriği uygulamanın kullanıcı arayüzünde gösteriyorsa ve yakalanan uygulama da kullanıcı tarafından görülebilir durumdaysa (bu geri çağırma aracılığıyla belirtildiği gibi) kullanıcı aynı içeriği iki kez görür. Uygulamanızın kullanıcı arayüzünü güncellemek için geri çağırma işlevini kullanarak yakalanan içeriği gizleyin ve uygulamanızdaki düzen alanında diğer içerikler için yer açın.

  • onCapturedContentResize(): Ana makine uygulamasının, yakalanan görüntü bölgesinin boyutuna göre sanal ekrandaki medya projeksiyonunun ve medya projeksiyonu Surface boyutunu değiştirmesini sağlar.

    Yakalanan içerik (tek bir uygulama penceresi veya cihazın tamamının ekranı) boyut değiştirdiğinde (cihazın döndürülmesi veya yakalanan uygulamanın farklı bir pencere moduna girmesi nedeniyle) tetiklenir. En boy oranının yakalanan içerikle eşleştiğinden ve yakalamanın sinemaskop olmadığından emin olmak için hem sanal ekranı hem de yüzeyi yeniden boyutlandırmak üzere bu API'yi kullanın.

Kaynak kurtarma

Uygulamanız, medya projeksiyon oturumu durdurulduğunda ve geçersiz hale geldiğinde bilgilendirilmek için MediaProjection onStop() geri çağırma işlevini kaydetmelidir. Oturum durdurulduğunda uygulamanız, sanal ekran ve projeksiyon yüzeyi gibi sahip olduğu kaynakları serbest bırakmalıdır. Uygulamanız daha önce bu medya projeksiyonu için sanal ekran oluşturmamış olsa bile durdurulan bir medya projeksiyonu oturumu artık yeni bir sanal ekran oluşturamaz.

Sistem, medya projeksiyonu sona erdiğinde geri çağırma işlevini çağırır. Bu fesih, aşağıdakiler gibi çeşitli nedenlerden kaynaklanabilir:

  • Kullanıcı, uygulamanın kullanıcı arayüzünü veya sistemin medya yansıtma durum çubuğu çipini kullanarak oturumu durdurur.
  • Ekran kilitleniyor
  • Başka bir medya projeksiyonu oturumu başlar
  • uygulama işlemi sonlandırılır.

Uygulamanız geri aramayı kaydetmezse createVirtualDisplay() numaralı telefona yapılan tüm aramalar IllegalStateException hatası verir.

Devre dışı bırak

Android 14 veya sonraki sürümler, uygulama ekranı paylaşımını varsayılan olarak etkinleştirir. Her medya yansıtma oturumunda kullanıcılara bir uygulama penceresini veya ekranın tamamını paylaşma seçeneği sunulur.

Uygulamanız, createConfigForDefaultDisplay() çağrısından döndürülen bir MediaProjectionConfig bağımsız değişkeniyle createScreenCaptureIntent(MediaProjectionConfig) yöntemini çağırarak uygulama ekranı paylaşımını devre dışı bırakabilir.

createConfigForUserChoice() çağrısından döndürülen MediaProjectionConfig bağımsız değişkeni içeren createScreenCaptureIntent(MediaProjectionConfig) çağrısı, varsayılan davranışla (yani createScreenCaptureIntent() çağrısıyla) aynıdır.

Yeniden boyutlandırılabilir uygulamalar

Medya projeksiyon uygulamalarınızı her zaman yeniden boyutlandırılabilir yapın (resizeableActivity="true"). Yeniden boyutlandırılabilir uygulamalar, cihaz yapılandırması değişikliklerini ve çoklu pencere modunu destekler (Çoklu pencere desteği bölümüne bakın).

Uygulamanız yeniden boyutlandırılamıyorsa görüntüleme sınırlarını bir pencere bağlamında sorgulamalı ve uygulamanın kullanabileceği maksimum görüntüleme alanının WindowMetrics değerini almak için getMaximumWindowMetrics() kullanmalıdır :

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

Durum çubuğu çipi ve otomatik durdurma

Ekran yansıtma istismarlarında, kullanıcılar cihaz ekranlarının paylaşıldığını fark etmediğinden finansal bilgiler gibi gizli kullanıcı verileri açığa çıkar.

Android 15 (API düzeyi 35) QPR1, büyük ve belirgin bir yeni durum çubuğu çipi sunar. Bu çip, kullanıcıları devam eden ekran yansıtma işlemleri konusunda uyarır. Kullanıcılar, ekranlarının paylaşılmasını, aktarılmasını veya kaydedilmesini durdurmak için çipe dokunabilir.

Android 15 QPR1 ve sonraki sürümlerde, cihaz ekranı kilitlendiğinde ekran yansıtma otomatik olarak durdurulur.

Şekil 2. Ekran paylaşımı, ekran yayınlama ve ekran kaydı için durum çubuğu çipi.

Ek kaynaklar

Medya yansıtma hakkında daha fazla bilgi için Video ve ses oynatmayı yakalama başlıklı makaleyi inceleyin.