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

Pencere içinde pencere (PiP) Jetpack Kitaplığı, Android uygulama geliştiricilerin PiP işlevini (özellikle medya oynatma, görüntülü iletişim ve gezinme uygulamaları için) uygulamasına yönelik kolay ve sağlam bir çözüm sunar. Kitaplık, birleşik bir API sağlayarak standart kodu ortadan kaldırmaya, uygulamalardaki yaygın hataları gidermeye ve genel olarak PiP kullanıcı deneyiminin kalitesini artırmaya yardımcı olur.

PiP Jetpack kitaplığı, Android ekosistemindeki çeşitli temel 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ümlerinde PiP API çağrılarındaki farklılıkları otomatik olarak işler. Örneğin, Android 12'den önce enterPictureInPictureMode, sonra ise isAutoEnterEnabled kullanılır. Böylece geliştiricilerin sürüm farklılıklarını yönetmesi gerekmez.
  • Hatalı PiP parametreleri: Medya oynatma sırasında sorunsuz ve yüksek kaliteli animasyonlar oluşturmak için setSourceRectHint gibi PiP parametrelerini 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, tek bir birleştirilmiş geri çağırma arayüzünde (PictureInPictureDelegate.OnPictureInPictureEventListener) birleştirilir.
  • Şablon kodunu 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 tekrarlanan şablon kodunun miktarını azaltır.
  • Geleceğe hazırlık: Diğer PiP özellikleri Jetpack kitaplığı aracılığıyla sunulur. Bu sayede, bu özellikleri kullananlar minimum çabayla ek işlevlere erişebilir.

Taşıma İş Akışı

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

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

Belirlenecek eski PiP mantığı:

  • onUserLeaveHint
  • setAutoEnterEnabled
  • onPictureInPictureModeChanged
  • onPictureInPictureUiStateChanged
  • setPictureInPictureParams.

2. AndroidManifest Yapılandırması

Gereksiz yeniden başlatmaları önlemek için PiP'e giren Etkinliğin, gerekli configChanges ile AndroidManifest.xml içinde desteği bildirdiğinden emin olun:

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

3. Ortam Kurulumu

build.gradle'ya gerekli bağımlılıkları 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 yeni AndroidX kitaplıklarını kullanın ve bu bilgiler 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:

  • Gezinme 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. Uygulama, mevcut uygulamasına bağlı olarak karmaşıklık ve maliyet açısından farklılık gösterecektir.

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

Uygulama, gezinmenin etkin veya devre dışı durumu hakkında kitaplığı bilgilendirir ve en-boy oranını ayarlar. Gerisini Jetpack kitaplığı halleder.

Temel farklar:

  1. Uygulama tarafında otomatik giriş ve eski giriş arasında ayrım yapılması gerekmez.
  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ığı aramanın etkin veya etkin olmayan durumu hakkında bilgilendirir ve en boy oranını ayarlar.

Temel farklar:

  1. Uygulama tarafında otomatik giriş ve eski giriş arasında ayrım yapılması gerekmez.
  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ığı: setAutoEnterEnabledAndroid 12 ve sonraki sürümler için onUserLeaveHint veya Android 11 ve önceki sürümler için onUserLeaveHint gibi API'ye özgü mantığı setEnabled ile değiştirin. PiP uygunluk durumu her değiştiğinde bu tetiklenir.
  • Geri çağırmalar: onPictureInPictureModeChanged (düzen değiştirme) ve onPictureInPictureUiStateChanged (animasyon/durumlar) işlemlerini birleştirerek birleşik etkinlik tabanlı geri çağırma onPictureInPictureEvent oluşturun.
  • İşlemler ve Parametreler: Parametreleri, şablon örneğinde setActions ve setAspectRatio kullanarak her değiştiğinde güncelleyin.
  • Video Özel İşleme: Video uygulamalarında, kaynak dikdörtgen ipucu güncellemelerini otomatikleştirmek ve sorunsuz geçişler sağlamak için setPlayerView kullanın. ` ### 6. Temizleme

VideoPlaybackPictureInPicture için close numaralı telefonu arayarak onDispose veya onDestroy numaralı telefonu arayarak görüntüleme izleyicileri gibi kaynakları serbest bırakın.

Referans Uygulama Kalıpları

Uygulama örnekleri.

Gezinme 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()
            }
        }
    }
}