পিকচার-ইন-পিকচার (PiP) জেটপ্যাক লাইব্রেরিটি অ্যান্ড্রয়েড অ্যাপ ডেভেলপারদের জন্য PiP কার্যকারিতা বাস্তবায়নের একটি সুবিন্যস্ত ও শক্তিশালী সমাধান প্রদান করে, বিশেষত মিডিয়া প্লেব্যাক, ভিডিও কমিউনিকেশন এবং নেভিগেশন অ্যাপের ক্ষেত্রে। একটি সমন্বিত এপিআই (API) প্রদানের মাধ্যমে, এই লাইব্রেরিটি বয়লারপ্লেট কোড ও অ্যাপের সাধারণ বাগগুলো দূর করতে এবং PiP ব্যবহারকারীর অভিজ্ঞতার সামগ্রিক মান উন্নত করতে সাহায্য করে।
PiP Jetpack লাইব্রেরিটি অ্যান্ড্রয়েড ইকোসিস্টেম জুড়ে থাকা বেশ কিছু প্রধান প্রতিবন্ধকতা এবং অসঙ্গতির সমাধান করে বিদ্যমান PiP API-গুলোকে সহজতর করে তোলে:
- OS ফ্র্যাগমেন্টেশন : লাইব্রেরিটি বিভিন্ন অ্যান্ড্রয়েড সংস্করণে PiP API কলের পার্থক্যগুলি স্বয়ংক্রিয়ভাবে পরিচালনা করে, যেমন অ্যান্ড্রয়েড ১২-এর আগে
enterPictureInPictureModeএবং এর পরেisAutoEnterEnabledব্যবহার করা, ফলে ডেভেলপারদের সংস্করণের পার্থক্য পরিচালনা করার প্রয়োজন হয় না। - ভুল PiP প্যারামিটার : এটি মিডিয়া প্লেব্যাকের সময় মসৃণ এবং উচ্চ-মানের অ্যানিমেশন তৈরি করার জন্য, উদাহরণস্বরূপ
setSourceRectHintমতো PiP প্যারামিটারগুলো সঠিকভাবে সেট করার একটি সমন্বিত সমাধান প্রদান করে। - একীভূত PiP স্টেট কলব্যাক : এটি সরলীকৃত স্টেট এবং UI ব্যবস্থাপনার জন্য
onPictureInPictureModeChangedএবংonPictureInPictureUiStateChangedকে একটি একক, একীভূত কলব্যাক ইন্টারফেসে (PictureInPictureDelegate.OnPictureInPictureEventListener) একত্রিত করে। - বয়লারপ্লেট কোড হ্রাস : এই লাইব্রেরিটি প্লেব্যাক কন্ট্রোল এবং ভিডিও কল অ্যাকশনের মতো সাধারণ ব্যবহারের ক্ষেত্রগুলির জন্য পূর্বনির্ধারিত
RemoteActionsএর সেট প্রদান করে পুনরাবৃত্তিমূলক, বয়লারপ্লেট কোডের পরিমাণ কমিয়ে দেয়। - ভবিষ্যৎ-প্রস্তুতি : জেটপ্যাক লাইব্রেরির মাধ্যমে PiP-এর আরও বৈশিষ্ট্য সরবরাহ করা হয়, যা ব্যবহারকারীদের ন্যূনতম বা কোনো প্রচেষ্টা ছাড়াই অতিরিক্ত কার্যকারিতা ব্যবহারের সুযোগ দেয়।
মাইগ্রেশন ওয়ার্কফ্লো
অ্যাপটির ইউজ কেস ক্যাটাগরি এবং লিগ্যাসি PiP লজিক শনাক্ত করুন:
বিভাগসমূহ: ভিডিও প্লেব্যাক, নেভিগেশন, বা ভিডিও কল।
শনাক্ত করার জন্য লিগ্যাসি PiP লজিক:
-
onUserLeaveHint -
setAutoEnterEnabled -
onPictureInPictureModeChanged -
onPictureInPictureUiStateChanged -
setPictureInPictureParams.
২. অ্যান্ড্রয়েড ম্যানিফেস্ট কনফিগারেশন
অপ্রয়োজনীয় রিস্টার্ট এড়ানোর জন্য, 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; সাধারণত নির্বিঘ্ন আকার পরিবর্তন (seamless resize) সমর্থিত নয়, এবং আপনার কোনো সোর্স রেক্ট হিন্ট (source rect hint)-এর প্রয়োজন নেই। - ভিডিও প্লেব্যাক :
VideoPlaybackPictureInPicture; এটি সোর্স রেক্ট হিন্টের জন্য প্লেয়ার ভিউয়ের সীমানা স্বয়ংক্রিয়ভাবে ট্র্যাক করে এবং ডিফল্টরূপে নির্বিঘ্ন রিসাইজ সক্ষম করে।
জেটপ্যাক লাইব্রেরি ব্যবহার করার জন্য, আপনার বিদ্যমান কাস্টম PiP ইমপ্লিমেন্টেশনকে জেটপ্যাক লাইব্রেরি API দিয়ে প্রতিস্থাপন করুন। এটি ব্যবহারের জটিলতা এবং খরচ অ্যাপটির বর্তমান ইমপ্লিমেন্টেশনের উপর নির্ভর করে ভিন্ন হবে।
নিম্নলিখিত বিভাগগুলিতে PiP-এর কিছু সাধারণ ব্যবহার এবং প্রয়োজনীয় বাস্তবায়ন ধাপসমূহ বর্ণনা করা হয়েছে:
নেভিগেশন
অ্যাপটি লাইব্রেরিকে নেভিগেশনের সক্রিয় বা নিষ্ক্রিয় অবস্থা সম্পর্কে জানায় এবং এর অ্যাস্পেক্ট রেশিও নির্ধারণ করে। বাকি কাজটা জেটপ্যাক লাইব্রেরি সামলে নেয়।
মূল পার্থক্য:
- অ্যাপের দিক থেকে অটো-এন্টার এবং লেগ্যাসি-এন্টার-এর মধ্যে পার্থক্য করার প্রয়োজন নেই।
- সমন্বিত কলব্যাক ইন্টারফেসসমূহ।
- পূর্ববর্তী সংস্করণের সাথে সামঞ্জস্যের জন্য নতুন
PictureInPictureParamsবিল্ডার।
ভিডিও কল
অ্যাপটি লাইব্রেরিকে কলটির সক্রিয় বা নিষ্ক্রিয় অবস্থা সম্পর্কে জানায় এবং অ্যাস্পেক্ট রেশিও সেট করে।
মূল পার্থক্য:
- অ্যাপের দিক থেকে অটো-এন্টার এবং লেগ্যাসি-এন্টার-এর মধ্যে পার্থক্য করার প্রয়োজন নেই।
- সমন্বিত কলব্যাক ইন্টারফেসসমূহ।
- পূর্ববর্তী সংস্করণের সাথে সামঞ্জস্যের জন্য নতুন
PictureInPictureParamsবিল্ডার। - ভিডিও কলের জন্য প্রমিত অ্যাকশন আইকন।
৫. কোড মাইগ্রেশন
- এন্ট্রি লজিক: অ্যান্ড্রয়েড ১২ এবং তার উপরের সংস্করণের জন্য
setAutoEnterEnabled, অথবা অ্যান্ড্রয়েড ১১ এবং তার নিচের সংস্করণের জন্যonUserLeaveHintএর মতো এপিআই-নির্দিষ্ট লজিককেsetEnabledদিয়ে প্রতিস্থাপন করুন। যখনই PiP যোগ্যতার স্থিতি পরিবর্তিত হবে, তখনই এটি ট্রিগার করুন। - কলব্যাক:
onPictureInPictureModeChanged(লেআউট টগলিং) এবংonPictureInPictureUiStateChanged(অ্যানিমেশন/স্টেট) - এই দুটিকে একত্রিত করেonPictureInPictureEventনামক একটি একক ইভেন্ট-ভিত্তিক কলব্যাকে পরিণত করা হয়েছে। - অ্যাকশন ও প্যারামিটার: প্যারামিটারগুলো পরিবর্তিত হলে, টেমপ্লেট ইনস্ট্যান্সে
setActionsএবংsetAspectRatioব্যবহার করে সেগুলো আপডেট করুন। - ভিডিও বিশেষ পরিচালনা: ভিডিও অ্যাপের জন্য, সোর্স রেক্ট হিন্ট আপডেট স্বয়ংক্রিয় করতে এবং মসৃণ ট্রানজিশন নিশ্চিত করতে
setPlayerViewব্যবহার করুন। ` ### ৬. পরিষ্করণ
VideoPlaybackPictureInPicture ক্ষেত্রে, ভিউ ট্র্যাকারের মতো রিসোর্সগুলো মুক্ত করতে onDispose বা onDestroy এ close কল করুন।
রেফারেন্স বাস্তবায়ন প্যাটার্ন
বাস্তবায়নের উদাহরণসমূহ।
নেভিগেশন এবং ভিডিও কল
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() } } } }