Jetpack Pencere İçinde Pencere Kitaplığı'nı kullanma

Pencere içinde pencere (PiP) Jetpack kitaplığı, Android uygulama geliştiricilerine özellikle medya oynatma, görüntülü iletişim ve navigasyon uygulamaları için PiP işlevini uygulamak üzere kolaylaştırılmış ve sağlam bir çözüm sunar. Birleşik bir API sunan kitaplık, ortak metin kodunu ve yaygın uygulama içi hataları ortadan kaldırmaya yardımcı olur ve PiP kullanıcı deneyiminin genel kalitesini artırır.

PiP Jetpack kitaplığı, Android ekosistemindeki bazı önemli zorlukları ve tutarsızlıkları ele alarak mevcut PiP API'lerini kolaylaştırır:

  • OS parçalanması: Kitaplık, çeşitli Android sürümlerindeki PiP API çağrılarındaki farklılıkları otomatik olarak yönetir. Örneğin, Android 12'den önce enterPictureInPictureMode, Android 12'den sonra ise isAutoEnterEnabled kullanılır. Bu sayede geliştiricilerin sürüm farklılıklarını yönetmesi gerekmez.
  • Yanlış PiP parametreleri: Medya oynatma sırasında sorunsuz ve yüksek kaliteli animasyonlar oluşturmak için PiP parametrelerini (ör. setSourceRectHint) doğru şekilde ayarlamaya yönelik birleşik bir çözüm sunar.
  • Birleştirilmiş PiP durumu geri çağırmaları: Durum ve kullanıcı arayüzü yönetimini basitleştirmek için onPictureInPictureModeChanged ve onPictureInPictureUiStateChanged'yı tek bir birleştirilmiş geri çağırma arayüzünde (PictureInPictureDelegate.OnPictureInPictureEventListener) birleştirir.
  • Ortak metin kodu azaltma: Kitaplık, oynatma kontrolleri ve görüntülü görüşme işlemleri gibi yaygın kullanım alanları için önceden tanımlanmış RemoteActions kümeleri sunarak tekrarlayan ortak metin kodu miktarını azaltır.
  • Geleceğe hazırlık: Diğer PiP özellikleri Jetpack kitaplığı üzerinden sunulur. Bu sayede kullanıcılar, ek işlevlere minimum çabayla veya hiç çaba harcamadan erişebilir.

Taşıma İş Akışı

Uygulamanın kullanım alanı kategorisini ve eski PiP mantığını belirleyin:

Kategoriler: Video Oynatma, Navigasyon veya Görüntülü Görüşme.

Tanımlanacak Eski PiP Mantığı:

  • onUserLeaveHint
  • setAutoEnterEnabled
  • onPictureInPictureModeChanged
  • onPictureInPictureUiStateChanged
  • setPictureInPictureParams.

2. AndroidManifest Yapılandırması

PiP'ye giren etkinliğin, gereksiz yeniden başlatmaları önlemek için gerekli configChanges ile AndroidManifest.xml içinde desteği beyan ettiğinden emin olun:

<activity
android:name="VideoActivity" android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
</activity>

3. Ortam Kurulumu

Gerekli bağımlılıkları build.gradle dosyasına ekleyin:

dependencies {
implementation("androidx.core:core:1.18.0")
implementation("androidx.activity:activity:1.13.0")
implementation("androidx.core:core-pip:1.0.0-alpha02") }

Bağımlılıklar için en son AndroidX kitaplıklarını kullanın ve bu bilgi için sürümler sayfasına bakın.

4. Şablon seçimi ve başlatma

Uygulamanın kullanım alanına en uygun uygulama şablonunu seçin:

  • Navigasyon ve görüntülü görüşme: BasicPictureInPicture; sorunsuz yeniden boyutlandırma genellikle desteklenmez ve kaynak dikdörtgen ipucuna ihtiyacınız yoktur.
  • Video oynatma: VideoPlaybackPictureInPicture; kaynak dikdörtgen ipucu için oynatıcı görünüm sınırlarını otomatik olarak izler ve varsayılan olarak sorunsuz yeniden boyutlandırmayı etkinleştirir.

Jetpack kitaplığını kullanmak için mevcut özel PiP uygulamanızı Jetpack kitaplığı API'leriyle değiştirin. Geçişin karmaşıklığı ve maliyeti, uygulamanın mevcut uygulamasına göre değişiklik gösterir.

Aşağıdaki bölümlerde, PiP'nin tipik kullanım alanlarından bazıları ve gerekli uygulama adımları açıklanmaktadır:

Uygulama, kitaplığa navigasyonun etkin veya etkin olmayan durumunu bildirir ve en boy oranını ayarlar. Gerisini Jetpack kitaplığı halleder.

Temel farklar:

  1. Uygulama tarafında otomatik giriş ile eski giriş arasında ayrım yapılmasına gerek yoktur.
  2. Geri çağırma arayüzleri birleştirildi.
  3. Geriye dönük uyumluluk için yeni PictureInPictureParams oluşturucu.

Görüntülü Görüşme

Uygulama, kitaplığa çağrının etkin veya etkin olmayan durumu hakkında bilgi verir ve en boy oranını ayarlar.

Temel farklar:

  1. Uygulama tarafında otomatik giriş ile eski giriş arasında ayrım yapılmasına gerek yoktur.
  2. Geri çağırma arayüzleri birleştirildi.
  3. Geriye dönük uyumluluk için yeni PictureInPictureParams oluşturucu.
  4. Görüntülü görüşme için standartlaştırılmış işlem simgeleri.

5. Kod Taşıma

  • Giriş mantığı: Android 12 ve sonraki sürümler için setAutoEnterEnabled veya Android 11 ve önceki sürümler için onUserLeaveHint gibi API'ye özel mantığı setEnabled ile değiştirin. PiP uygunluk durumu değiştiğinde bunu tetikleyin.
  • Geri çağırmalar: onPictureInPictureModeChanged (düzen değiştirme) ve onPictureInPictureUiStateChanged (animasyon/durumlar) etkinliklerini birleştirerek tek bir etkinlik tabanlı geri çağırma onPictureInPictureEvent oluşturun.
  • İşlemler ve Parametreler: Şablon örneğindeki parametreleri, her değiştiğinde setActions ve setAspectRatio kullanarak güncelleyin.

Referans Uygulama Modelleri

Uygulama örnekleri.

Navigasyon ve Görüntülü Görüşme

class NavOrVideoCallJpipActivity : ComponentActivity(), PictureInPictureDelegate.OnPictureInPictureEventListener {
    private lateinit var pictureInPictureImpl: BasicPictureInPicture
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        pictureInPictureImpl = BasicPictureInPicture(this)
        // BasicPictureInPicture is ideal for Navigation and Video call use cases.
        pictureInPictureImpl.addOnPictureInPictureEventListener(
            ContextCompat.getMainExecutor(this),
            this
        )
        setContent {
        }
    }
    override fun onPictureInPictureEvent(
        event: PictureInPictureDelegate.Event,
        config: Configuration?
    ) {
        when (event) {
            PictureInPictureDelegate.Event.ENTERED -> { /* Toggle to PiP layout */ }
            PictureInPictureDelegate.Event.EXITED -> { /* Toggle to Full-screen layout */ }
            PictureInPictureDelegate.Event.STASHED -> { /* Optional: PiP is stashed */ }
            PictureInPictureDelegate.Event.UNSTASHED -> { /* Optional: PiP is unstashed */ }
        }
    }
}

Video Oynatma

class VideoPlaybackJpipActivity : ComponentActivity(), PictureInPictureDelegate.OnPictureInPictureEventListener {
    private lateinit var pictureInPictureImpl: VideoPlaybackPictureInPicture
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        pictureInPictureImpl = VideoPlaybackPictureInPicture(this)
        pictureInPictureImpl.addOnPictureInPictureEventListener(
            ContextCompat.getMainExecutor(this),
            this
        )
        setContent {
            ContentScreen(pictureInPictureImpl)
        }
    }
    override fun onPictureInPictureEvent(
        event: PictureInPictureDelegate.Event,
        config: Configuration?
    ) {
        when (event) {
            PictureInPictureDelegate.Event.ENTER_ANIMATION_START -> { /* Hide overlays */ }
            PictureInPictureDelegate.Event.ENTER_ANIMATION_END -> { /* Animation finished */ }
            PictureInPictureDelegate.Event.ENTERED -> { /* Switch to PiP layout */ }
            PictureInPictureDelegate.Event.STASHED -> { /* PiP stashed */ }
            PictureInPictureDelegate.Event.UNSTASHED -> { /* PiP unstashed */ }
            PictureInPictureDelegate.Event.EXITED -> { /* Return to full-screen */ }
        }
    }

    @Composable
    fun ContentScreen(pipController: VideoPlaybackPictureInPicture) {
        DisposableEffect(pipController) {
            onDispose {
                pipController.close()
            }
        }
    }
}