Medya tahmini

Android 5'te (API düzeyi 21) kullanıma sunulan android.media.projection API'leri, bir cihaz ekranının içeriğini medya akışı olarak yakalamanızı sağlar. Bu API'leri oynatabilir, kaydedebilir veya TV gibi diğer cihazlara yayınlayabilirsiniz.

Android 14 (API düzeyi 34), kullanıcıların pencere modundan bağımsız olarak tüm cihaz ekranı yerine tek bir uygulama penceresini paylaşmalarını sağlayan uygulama ekranı paylaşımını kullanıma sundu. Uygulama ekran paylaşımında durum çubuğu, gezinme çubuğu, bildirimler ve diğer sistem kullanıcı arayüzü öğeleri, bir uygulamayı tam ekran olarak yakalamak için kullanılsa bile paylaşılan ekrandan hariç tutulur. Yalnızca seçilen uygulamanın içeriği paylaşılır.

Uygulama ekran paylaşımı, kullanıcıların birden fazla uygulamayı çalıştırmasını sağlarken içerik paylaşımını tek bir uygulamayla kısıtlayarak kullanıcı gizliliğini korur, kullanıcı verimliliğini artırır ve çoklu görev deneyimini iyileştirir.

Üç ekran temsili

Medya projeksiyonu, bir cihaz ekranının veya uygulama penceresinin içeriğini yakalar ve daha sonra, yakalanan görüntüyü Surface'da oluşturan sanal bir ekrana yansıtır.

Sanal ekrana yansıtılan gerçek cihaz ekranı. Uygulama tarafından sağlanan "Surface"e yazılan sanal görüntülü reklam içeriği.
Şekil 1. Sanal ekrana yansıtılan gerçek cihaz ekranı veya uygulama penceresi. Uygulama tarafından sağlanan Surface öğesine yazılan sanal görüntü.

Uygulama, Surface öğelerini MediaRecorder, SurfaceTexture veya ImageReader aracılığıyla sağlar. Bu da, yakalanan ekranın içeriğini tüketen ve Surface üzerinde oluşturulan görüntüleri gerçek zamanlı olarak yönetebilmenizi sağlar. Resimleri kayıt olarak kaydedebilir veya TV'ye ya da başka bir cihaza yayınlayabilirsiniz.

Gerçek görüntülü reklam

Uygulamanıza cihaz ekranının veya uygulama penceresinin içeriklerini yakalama olanağı veren bir jeton alarak bir 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 bir MediaProjection örneği oluşturmak için MediaProjectionManager sistem hizmetinin getMediaProjection() yöntemini kullanın. Bir ekran görüntüsü alma işlemi belirtmek için etkinliği createScreenCaptureIntent() yönteminden bir niyetle 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 görüntü

Medya projeksiyonunun en önemli kısmı, MediaProjection örneğinde createVirtualDisplay() yöntemini ç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 elde etmek için Android 11'de (API düzeyi 30) kullanıma sunulan WindowMetrics API'lerini kullanın. (Ayrıntılar için Medya projeksiyonu boyutu bölümüne bakın.)

Yüzey

Uygun çözünürlükte çıktı üretmek için medya projeksiyon yüzeyini boyutlandırın. TV'lere veya bilgisayar monitörlerine yayın yaparken yüzeyi büyük (düşük çözünürlüklü), cihaz ekranı kaydı için ise küçük (yüksek çözünürlüklü) kullanın.

Android 12L'den (API düzeyi 32) itibaren sistem, yakalanan içeriği yüzeyde oluştururken 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 karşılık gelen boyutlarına eşit veya bundan daha düşük olur. Yakalanan içerik daha sonra yüzeyde ortalanır.

Android 12L ölçeklendirme yaklaşımı, uygun en boy oranını sağlarken yüzey görüntüsünün boyutunu en üst düzeye çıkararak televizyonlara ve diğer büyük ekranlara ekran yayınını iyileştirir.

Ön plan hizmeti izni

Uygulamanız Android 14 veya sonraki bir sürümü hedefliyorsa uygulama manifesti mediaProjection ön plan hizmet türü için izin beyanı içermelidir:

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

Medya projeksiyonu hizmetini startForeground() çağrısıyla başlatın.

Çağrıda ön plan hizmet türünü belirtmezseniz tür için varsayılan olarak manifest'te tanımlanan ön plan hizmet türlerinin bit tabanlı bir tam sayısı kullanılır. Manifest herhangi bir hizmet türü belirtmiyorsa sistem MissingForegroundServiceTypeException değerini döndürür.

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

Android 14 veya sonraki sürümlerde uygulamanız aşağıdakilerden birini yaparsa createVirtualDisplay() yöntemi SecurityException döndürür:

  • createScreenCaptureIntent() öğesinden getMediaProjection() hedefine birden fazla kez döndürülen Intent örneğini iletir
  • createVirtualDisplay() numaralı telefonu aynı MediaProjection örneğinde birden çok kez çağırır

Medya projeksiyonu boyutu

Bir medya projeksiyonu, aralık modundan bağımsız olarak cihaz ekranının tamamını veya bir uygulama penceresini yakalayabilir.

Başlangıç boyutu

Tam ekran medya projeksiyonu kullanıldığında, uygulamanızın cihaz ekranının boyutunu belirlemesi gerekir. Uygulama ekran paylaşımında, kullanıcı yakalama bölgesini seçene kadar uygulamanız yakalanan ekranın boyutunu belirleyemez. Dolayısıyla, herhangi bir medya projeksiyonunun ilk boyutu cihaz ekranının boyutudur.

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

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

Cihaz ekranının genişliğini ve yüksekliğini öğrenmek 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. Yakalanan içerik, medya projeksiyonu ayarlandığında elde edilen maksimum pencere metriklerinden farklı bir boyuttaysa medya projeksiyonu sinemaskoplu olabilir.

Medya projeksiyonunun, yakalanan herhangi bir bölge ve cihaz döndürmeleri için yakalanan içeriğin boyutuyla tam olarak uyumlu olmasını sağlamak amacıyla, yakalamayı yeniden boyutlandırmak üzere onCapturedContentResize() geri çağırmasını kullanın. (Daha fazla bilgi için aşağıdaki Özelleştirme bölümüne bakın).

Özelleştirme

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

  • onCapturedContentVisibilityChanged(): Barındıran uygulamanın (medya projeksiyonunu başlatan uygulama) paylaşılan içeriği göstermesini veya gizlemesini sağlar.

    Yakalanan bölgenin kullanıcı tarafından görünür olup olmadığına bağlı olarak uygulamanızın kullanıcı arayüzünü özelleştirmek için bu geri çağırmayı kullanın. Örneğin, uygulamanız kullanıcı tarafından görülebiliyorsa ve yakalanan içeriği uygulamanın kullanıcı arayüzünde görüntülüyorsa ve yakalanan uygulama da kullanıcı tarafından görülebiliyorsa (bu geri çağırmada belirtildiği üzere) kullanıcı aynı içeriği iki kez görür. Yakalanan içeriği gizlemek ve uygulamanızda başka içerikler için düzen alanı açmak amacıyla geri çağırma işlevini kullanarak uygulamanızın kullanıcı arayüzünü güncelleyin.

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

    Yakalanan içerik (tek uygulama penceresi veya tam cihaz ekranı) boyut değiştirdiğinde tetiklenir (cihazın döndürülmesi veya yakalanan uygulamanın farklı bir aralık moduna girmesi nedeniyle). 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 için bu API'yi kullanın.

Kaynak kurtarma

Uygulamanız, uygulama tarafından tutulan sanal ekran ve projeksiyon yüzeyi gibi kaynakları serbest bırakmak için MediaProjection onStop() geri çağırmasını kaydetmelidir.

Medya projeksiyonu sona erdiğinde veya kullanıcı yakalama oturumuna devam etmek için izin vermediğinde geri çağırma çağrılır.

Uygulamanız geri çağırmayı kaydetmezse ve kullanıcı medya projeksiyonu oturumuna izin vermezse createVirtualDisplay(), IllegalStateException çağrısını gönderir.

Devre dışı bırak

Android 14 veya sonraki sürümlerde uygulama ekran paylaşımı varsayılan olarak etkindir. Her medya projeksiyonu oturumu, kullanıcılara bir uygulama penceresini veya ekranın tamamını paylaşma seçeneği sunar.

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

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

Yeniden boyutlandırılabilir uygulamalar

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

Uygulamanız yeniden boyutlandırılabilir değilse bir pencere içeriğinden görüntüleme sınırlarını sorgulaması ve uygulama tarafından kullanılabilen maksimum görüntüleme alanının WindowMetrics'ını almak için getMaximumWindowMetrics() kullanması gerekir :

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

Ek kaynaklar

Medya projeksiyonu hakkında daha fazla bilgi için Video kaydetme ve ses oynatma bölümüne bakın.