Jetpack की पिक्चर में पिक्चर लाइब्रेरी का इस्तेमाल करना

पिक्चर में पिक्चर (पीआईपी) Jetpack लाइब्रेरी, Android ऐप्लिकेशन डेवलपर को पीआईपी की सुविधा लागू करने के लिए, एक बेहतर और आसान समाधान उपलब्ध कराती है. खास तौर पर, मीडिया चलाने, वीडियो कम्यूनिकेशन, और नेविगेशन ऐप्लिकेशन के लिए. यह लाइब्रेरी, एक यूनिफ़ाइड एपीआई उपलब्ध कराती है. इससे बॉयलरप्लेट कोड और ऐप्लिकेशन में होने वाली सामान्य गड़बड़ियों को ठीक करने में मदद मिलती है. साथ ही, PiP मोड में उपयोगकर्ता अनुभव की क्वालिटी को बेहतर बनाया जा सकता है.

PiP Jetpack लाइब्रेरी, मौजूदा PiP API को बेहतर बनाती है. साथ ही, Android इकोसिस्टम में आने वाली कई मुख्य चुनौतियों और गड़बड़ियों को ठीक करती है:

  • ओएस फ़्रैगमेंटेशन: यह लाइब्रेरी, अलग-अलग Android वर्शन पर PiP API कॉल में होने वाले अंतर को अपने-आप मैनेज करती है. जैसे, Android 12 से पहले enterPictureInPictureMode और बाद में isAutoEnterEnabled का इस्तेमाल करना. इसलिए, डेवलपर को वर्शन के अंतर को मैनेज करने की ज़रूरत नहीं होती.
  • PiP के पैरामीटर गलत होना: यह सुविधा, PiP के पैरामीटर को सही तरीके से सेट करने के लिए एक यूनिफ़ाइड समाधान उपलब्ध कराती है. उदाहरण के लिए, मीडिया चलाने के दौरान बेहतर और अच्छी क्वालिटी वाले ऐनिमेशन बनाने के लिए setSourceRectHint.
  • एक ही तरह के PiP स्टेट कॉलबैक: यह onPictureInPictureModeChanged और onPictureInPictureUiStateChanged को एक ही कॉलबैक इंटरफ़ेस (PictureInPictureDelegate.OnPictureInPictureEventListener) में इकट्ठा करता है, ताकि स्टेट और यूज़र इंटरफ़ेस (यूआई) को आसानी से मैनेज किया जा सके.
  • बॉयलरप्लेट कोड कम करना: यह लाइब्रेरी, बार-बार इस्तेमाल होने वाले बॉयलरप्लेट कोड की मात्रा को कम करती है. इसके लिए, यह सामान्य इस्तेमाल के मामलों के लिए, पहले से तय किए गए RemoteActions के सेट उपलब्ध कराती है. जैसे, वीडियो चलाने के कंट्रोल और वीडियो कॉल की कार्रवाइयां.
  • आने वाले समय के लिए तैयार: PiP की अन्य सुविधाएँ, Jetpack लाइब्रेरी के ज़रिए उपलब्ध कराई जाती हैं. इससे, PiP की सुविधा इस्तेमाल करने वाले लोग, बिना किसी परेशानी के अतिरिक्त सुविधाओं का ऐक्सेस पा सकते हैं.

माइग्रेशन वर्कफ़्लो

ऐप्लिकेशन के इस्तेमाल के उदाहरण की कैटगरी और लेगसी PiP लॉजिक की पहचान करें:

कैटेगरी: वीडियो चलाना, नेविगेशन या वीडियो कॉल.

PiP की सुविधा को चालू करने के लिए, पुराने लॉजिक का इस्तेमाल किया गया है:

  • onUserLeaveHint
  • setAutoEnterEnabled
  • onPictureInPictureModeChanged
  • onPictureInPictureUiStateChanged
  • setPictureInPictureParams.

2. AndroidManifest कॉन्फ़िगरेशन

पक्का करें कि PiP मोड में जाने वाली Activity, AndroidManifest.xml में सहायता देने का एलान करे. साथ ही, बिना वजह रीस्टार्ट होने से रोकने के लिए, ज़रूरी configChanges का इस्तेमाल करे:

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

3. एनवायरमेंट सेटअप करना

build.gradle में ज़रूरी डिपेंडेंसी जोड़ें:

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

डिपेंडेंसी के लिए, AndroidX की नई लाइब्रेरी का इस्तेमाल करें. साथ ही, इस बारे में जानकारी पाने के लिए, रिलीज़ पेज पर जाएं.

4. टेंप्लेट चुनना और उसे शुरू करना

लागू करने के लिए ऐसा टेंप्लेट चुनें जो ऐप्लिकेशन के इस्तेमाल के उदाहरण के हिसाब से सबसे सही हो:

  • नेविगेशन और वीडियो कॉल: BasicPictureInPicture; आम तौर पर, बिना किसी रुकावट के साइज़ बदलने की सुविधा काम नहीं करती है. साथ ही, आपको सोर्स रेक्ट हिंट की ज़रूरत नहीं होती.
  • वीडियो चलाना: VideoPlaybackPictureInPicture; यह सोर्स रेक्ट हिंट के लिए, प्लेयर के व्यू बाउंड को अपने-आप ट्रैक करता है. साथ ही, डिफ़ॉल्ट रूप से बिना किसी रुकावट के वीडियो का साइज़ बदलने की सुविधा चालू करता है.

Jetpack लाइब्रेरी का इस्तेमाल करने के लिए, PiP की सुविधा को लागू करने के मौजूदा तरीके को Jetpack लाइब्रेरी के एपीआई से बदलें. ऐप्लिकेशन में मौजूदा समय में लागू किए गए तरीके के आधार पर, इसे लागू करने में आने वाली मुश्किलों और लागत में अंतर होगा.

यहां दिए गए सेक्शन में, PiP के इस्तेमाल के कुछ सामान्य उदाहरणों के बारे में बताया गया है. साथ ही, इसे लागू करने के ज़रूरी चरणों के बारे में भी बताया गया है:

ऐप्लिकेशन, लाइब्रेरी को नेविगेशन के चालू या बंद होने की स्थिति के बारे में बताता है. साथ ही, यह पहलू का अनुपात सेट करता है. बाकी काम Jetpack लाइब्रेरी करती है.

मुख्य अंतर:

  1. ऐप्लिकेशन के लिए, ऑटो-एंटर और लेगसी-एंटर के बीच अंतर करने की ज़रूरत नहीं है.
  2. कॉलबैक इंटरफ़ेस को एक साथ इस्तेमाल करने की सुविधा.
  3. पुराने सिस्टम के साथ काम करने की सुविधा के लिए, नया PictureInPictureParams बिल्डर.

वीडियो कॉल

ऐप, लाइब्रेरी को कॉल के चालू या बंद होने की स्थिति के बारे में बताता है. साथ ही, यह आसपेक्ट रेशियो सेट करता है.

मुख्य अंतर:

  1. ऐप्लिकेशन के लिए, ऑटो-एंटर और लेगसी-एंटर के बीच अंतर करने की ज़रूरत नहीं है.
  2. कॉलबैक इंटरफ़ेस को एक साथ इस्तेमाल करने की सुविधा.
  3. पुराने सिस्टम के साथ काम करने की सुविधा के लिए, नया PictureInPictureParams बिल्डर.
  4. वीडियो कॉल के लिए स्टैंडर्ड ऐक्शन आइकॉन.

5. कोड माइग्रेशन

  • एंट्री लॉजिक: एपीआई के हिसाब से लॉजिक को बदलें. जैसे, setAutoEnterEnabled Android 12 और इसके बाद के वर्शन के लिए या onUserLeaveHint Android 11 और इसके पहले के वर्शन के लिए को setEnabled से बदलें. जब भी PiP की सुविधा इस्तेमाल करने की ज़रूरी शर्तों को पूरा करने की स्थिति में बदलाव हो, तब इस इवेंट को ट्रिगर करें.
  • कॉलबैक: onPictureInPictureModeChanged (लेआउट टॉगल करना) और onPictureInPictureUiStateChanged (ऐनिमेशन/स्टेट) को एक ही इवेंट पर आधारित कॉलबैक onPictureInPictureEvent में शामिल करें.
  • कार्रवाइयां और पैरामीटर: जब भी पैरामीटर में बदलाव हो, तब टेंप्लेट इंस्टेंस पर setActions और setAspectRatio का इस्तेमाल करके, पैरामीटर अपडेट करें.

रेफ़रंस के तौर पर लागू करने के पैटर्न

लागू करने के उदाहरण.

नेविगेशन और वीडियो कॉल

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 */ }
        }
    }
}

वीडियो प्लेबैक

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