Jetpack পিকচার-ইন-পিকচার লাইব্রেরি ব্যবহার করা

পিকচার-ইন-পিকচার (PiP) Jetpack লাইব্রেরি, PiP ফাংশনালিটি প্রয়োগ করার জন্য Android অ্যাপ ডেভেলপারদের একটি স্ট্রিমলাইন করা এবং শক্তিশালী সমাধান অফার করে, বিশেষ করে মিডিয়া প্লেব্যাক, ভিডিও কমিউনিকেশন এবং নেভিগেশন অ্যাপের জন্য। একটি ইউনিফায়েড API প্রদান করার মাধ্যমে, লাইব্রেরিটি বয়লারপ্লেট কোড, সাধারণ ইন-অ্যাপ বাগ দূর করতে এবং PiP ব্যবহারকারীর অভিজ্ঞতার সামগ্রিক কোয়ালিটি উন্নত করতে সাহায্য করে।

PiP Jetpack লাইব্রেরি, Android ইকোসিস্টেম জুড়ে থাকা একাধিক গুরুত্বপূর্ণ চ্যালেঞ্জ ও অসঙ্গতি সমাধান করার মাধ্যমে আগে থেকেই থাকা PiP API-কে আরও সহজ করে তোলে:

  • OS ফ্র্যাগমেন্টেশন: PiP API কলের ক্ষেত্রে বিভিন্ন Android ভার্সন জুড়ে থাকা পার্থক্য লাইব্রেরি অটোমেটিক ম্যানেজ করে, যেমন Android 12-এর আগে enterPictureInPictureMode এবং পরে isAutoEnterEnabled ব্যবহার করা, তাই ডেভেলপারদের ভার্সন পার্থক্য ম্যানেজ করতে হয় না।
  • ভুল PiP প্যারামিটার: এটি সঠিকভাবে PiP প্যারামিটার সেট করার জন্য একটি সমন্বিত সমাধান প্রদান করে, যেমন setSourceRectHint, যাতে মিডিয়া প্লেব্যাকের সময় মসৃণ ও হাই-কোয়ালিটি অ্যানিমেশন তৈরি করা যায়।
  • ইউনিফায়েড PiP স্টেট কলব্যাক: এটি onPictureInPictureModeChanged এবং onPictureInPictureUiStateChanged-কে একটি ইউনিফায়েড কলব্যাক ইন্টারফেসে (PictureInPictureDelegate.OnPictureInPictureEventListener) একত্রিত করে। এর ফলে স্টেট ও UI ম্যানেজমেন্ট সহজ হয়ে যায়।
  • বয়লারপ্লেট কোড কমানো: লাইব্রেরিটি আগে থেকে সংজ্ঞায়িত RemoteActions-এর সেট অফার করার মাধ্যমে পুনরাবৃত্তিমূলক, বয়লারপ্লেট কোডের পরিমাণ কমিয়ে দেয়। এটি প্লেব্যাক কন্ট্রোল এবং ভিডিও কল অ্যাকশনের মতো সাধারণ ব্যবহারের ক্ষেত্রে প্রযোজ্য।
  • ভবিষ্যতের জন্য উপযুক্ত করে তোলা: Jetpack লাইব্রেরির মাধ্যমে আরও PiP ফিচার প্রদান করা হয়, এর ফলে গ্রহণকারীরা ন্যূনতম থেকে কোনও প্রচেষ্টা ছাড়াই অতিরিক্ত কার্যকারিতা অ্যাক্সেস করতে পারেন।

মাইগ্রেশন ওয়ার্কফ্লো

অ্যাপের ব্যবহারিক কেস বিভাগ ও পুরনো PiP লজিক শনাক্ত করুন:

বিভাগ: ভিডিও প্লেব্যাক, নেভিগেশন বা ভিডিও কল।

শনাক্ত করার জন্য পুরনো PiP লজিক:

  • onUserLeaveHint
  • setAutoEnterEnabled
  • onPictureInPictureModeChanged
  • onPictureInPictureUiStateChanged
  • setPictureInPictureParams।

২. AndroidManifest কনফিগারেশন

PiP-এ প্রবেশ করা অ্যাক্টিভিটি যেন AndroidManifest.xml-এ প্রয়োজনীয় configChanges-এর সাথে সাপোর্ট ঘোষণা করে, তা নিশ্চিত করুন যাতে অপ্রয়োজনীয় রিস্টার্ট এড়ানো যায়:

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

৩. এনভায়রনমেন্ট সেট-আপ

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 লাইব্রেরি ব্যবহার করুন এবং সেই তথ্যের জন্য রিলিজ পৃষ্ঠা দেখুন।

৪. টেমপ্লেট বেছে নেওয়া ও শুরু করা

অ্যাপের ব্যবহারের ক্ষেত্রে সবচেয়ে উপযুক্ত ইমপ্লিমেন্টেশন টেমপ্লেট বেছে নিন:

  • নেভিগেশন ও ভিডিও কল: BasicPictureInPicture; সাধারণত নির্বিঘ্নে সাইজ পরিবর্তন করার সুবিধা কাজ করে না এবং সোর্স রেক্ট হিন্ট প্রয়োজন হয় না।
  • ভিডিও প্লেব্যাক: VideoPlaybackPictureInPicture; সোর্স রেক হিন্টের জন্য অটোমেটিক প্লেয়ার ভিউ বাউন্ড ট্র্যাক করে এবং ডিফল্ট হিসেবে নির্বিঘ্নে সাইজ পরিবর্তন করার সুবিধা চালু করে।

Jetpack লাইব্রেরি গ্রহণ করতে, আপনার বিদ্যমান কাস্টম PiP ইমপ্লিমেন্টেশনকে Jetpack লাইব্রেরি API-এর সাথে পরিবর্তন করুন। অ্যাপের বর্তমান প্রয়োগের উপর নির্ভর করে গ্রহণ করার জটিলতা ও খরচ পরিবর্তিত হবে।

নিচের বিভাগগুলিতে PiP-এর কিছু সাধারণ ব্যবহারের উদাহরণ এবং প্রয়োগের প্রয়োজনীয় ধাপগুলি বর্ণনা করা হয়েছে:

অ্যাপটি নেভিগেশনের অ্যাক্টিভ বা ইনঅ্যাক্টিভ অবস্থা সম্পর্কে লাইব্রেরিকে জানায় এবং অ্যাসপেক্ট রেশিও সেট করে। বাকি কাজ Jetpack লাইব্রেরি ম্যানেজ করে।

প্রধান পার্থক্য:

  1. অ্যাপের দিক থেকে অটো-এন্টার ও লেগ্যাসি-এন্টারের মধ্যে পার্থক্য করার প্রয়োজন নেই।
  2. সম্মিলিত কলব্যাক ইন্টারফেস।
  3. পুরনো ভার্সনের সাথে মানানসই হওয়ার জন্য নতুন PictureInPictureParams বিল্ডার।

ভিডিও কল করুন

অ্যাপটি লাইব্রেরিকে কলের অ্যাক্টিভ বা ইনঅ্যাক্টিভ অবস্থা সম্পর্কে জানায় এবং অ্যাসপেক্ট রেশিও সেট করে।

প্রধান পার্থক্য:

  1. অ্যাপের দিক থেকে অটো-এন্টার ও লেগ্যাসি-এন্টারের মধ্যে পার্থক্য করার প্রয়োজন নেই।
  2. সম্মিলিত কলব্যাক ইন্টারফেস।
  3. পুরনো ভার্সনের সাথে মানানসই হওয়ার জন্য নতুন PictureInPictureParams বিল্ডার।
  4. ভিডিও কলের জন্য স্ট্যান্ডার্ড অ্যাকশন আইকন।

৫. কোড মাইগ্রেশন

  • এন্ট্রি লজিক: API-নির্দিষ্ট লজিক যেমন 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()
            }
        }
    }
}