Medya projeksiyonu

Android 5'te (API seviyesi 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ızı sağlar.

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çerikleri 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 özelliğini iyileştirir.

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

Medya projeksiyonu, 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, yakalanan ekranın içeriklerini kullanan ve Surface'te oluşturulan resimleri anlık olarak yönetmenize olanak tanıyan bir MediaRecorder, SurfaceTexture veya ImageReader aracılığıyla Surface'yi 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 görüntüsü 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 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ğrısı yaparak 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() kaynağından döndürülen bir Intent örneğini getMediaProjection() kaynağına 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 makinesi 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 boyuta sahipse 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(): Barındıran 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 ekran bölgesinin boyutuna göre sanal ekrandaki medya projeksiyonunun ve medya projeksiyonu Surface boyutunu değiştirmesine olanak tanır.

    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 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 projeksiyonu 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ı) 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) ve sonraki sürümlerde, devam eden ekran yansıtma işlemleri hakkında kullanıcıları uyarmak için büyük ve belirgin bir durum çubuğu çipi gösterilir. Kullanıcılar, ekranlarının paylaşılmasını, aktarılmasını veya kaydedilmesini engellemek için çipe dokunabilir. Ayrıca, cihaz ekranı kilitlendiğinde ekran yansıtma otomatik olarak durdurulur.

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

Ekran paylaşımı, yayınlama veya kayıt başlatarak medya projeksiyonu durum çubuğu çipinin kullanılabilirliğini test edin. Çip, durum çubuğunda görünür.

Ekran yansıtma, kullanıcının durum çubuğu çipiyle etkileşime geçmesi veya kilit ekranının etkinleştirilmesi nedeniyle durdurulduğunda uygulamanızın kaynakları serbest bırakmasını ve kullanıcı arayüzünü güncellemesini sağlamak için aşağıdakileri yapın:

  • MediaProjection.Callback örneği oluşturun.

  • Geri çağırma onStop() yöntemini uygulayın. Ekran yansıtma durdurulduğunda bu yöntem çağrılır. Uygulamanızın kullandığı tüm kaynakları serbest bırakın ve uygulama kullanıcı arayüzünü gerektiği gibi güncelleyin.

Geri aramayı test etmek için durum çubuğu çipine dokunun veya ekran yansıtmayı durdurmak için cihaz ekranını kilitleyin. onStop() yönteminin çağrıldığını ve uygulamanızın amaçlandığı şekilde yanıt verdiğini doğrulayın.

Ek kaynaklar

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