Android-এ মিডিয়া কন্ট্রোল 'দ্রুত সেটিংস'-এর কাছাকাছি থাকে। একাধিক অ্যাপ থেকে সেশন সোয়াইপ করা যায় এমন ক্যারোজেলে সাজানো হয়। এই ক্রমে ক্যারোসেলে সেশন তালিকাভুক্ত করা হয়:
- ফোনে স্থানীয়ভাবে স্ট্রিম চালানো হচ্ছে
- রিমোট স্ট্রিম, যেমন এক্সটার্নাল ডিভাইস বা কাস্ট সেশনে শনাক্ত করা স্ট্রিম
- আগের সেশন যেগুলি আবার চালু করা যাবে, সেগুলি শেষবার যেভাবে চালানো হয়েছিল সেই ক্রমে সাজানো আছে
Android 13 (API লেভেল 33) থেকে শুরু করে, ব্যবহারকারীরা যাতে মিডিয়া প্লে করা অ্যাপের জন্য মিডিয়া কন্ট্রোলের
একটি সমৃদ্ধ সেট অ্যাক্সেস করতে পারেন তা নিশ্চিত করতে, মিডিয়া কন্ট্রোলের অ্যাকশন বোতামগুলি
Player স্টেট থেকে নেওয়া হয়।
এইভাবে, আপনি বিভিন্ন ডিভাইস জুড়ে মিডিয়া কন্ট্রোলের একটি সামঞ্জস্যপূর্ণ সেট এবং আরও উন্নত মিডিয়া কন্ট্রোলের অভিজ্ঞতা প্রদান করতে পারবেন।
ফোন ও ট্যাবলেট ডিভাইসে এটি কেমন দেখায় তার উদাহরণ যথাক্রমে ছবি ১-এ দেখানো হয়েছে,
সিস্টেম Player-এর অবস্থার উপর ভিত্তি করে সর্বাধিক পাঁচটি অ্যাকশন বোতাম দেখায়, যেমনটি
নিচের সারণীতে বর্ণনা করা হয়েছে। কমপ্যাক্ট মোডে, শুধুমাত্র প্রথম তিনটি অ্যাকশন
স্লট দেখানো হয়। Auto, Assistant ও Wear OS-এর মতো অন্যান্য Android প্ল্যাটফর্মে মিডিয়া কন্ট্রোল যেভাবে রেন্ডার করা হয়, এটি তার সাথে সামঞ্জস্যপূর্ণ।
| স্লট | নির্ণায়ক | অ্যাকশন |
|---|---|---|
| 1 |
playWhenReady মিথ্যা অথবা বর্তমান
প্লেব্যাক স্টেট হল STATE_ENDED।
|
চালান |
playWhenReady সত্য এবং বর্তমান
প্লেব্যাক স্ট্যাটাস হল STATE_BUFFERING।
|
স্পিনার লোড হচ্ছে | |
playWhenReady সত্য এবং বর্তমান
প্লেব্যাক স্ট্যাটাস হল STATE_READY।
|
পজ করুন | |
| 2 |
মিডিয়া
বোতাম সংক্রান্ত পছন্দ-এ CommandButton.SLOT_BACK-এর জন্য
কাস্টম বোতাম থাকে
|
কাস্টম |
প্লেয়ার কমান্ড
COMMAND_SEEK_TO_PREVIOUS অথবা
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM উপলভ্য।
|
পূর্ববর্তী | |
| কাস্টম বোতাম বা তালিকাভুক্ত কমান্ডের মধ্যে কোনওটিই উপলভ্য নেই। | ফাঁকা | |
| 3 |
মিডিয়া বোতাম
পছন্দ-এ CommandButton.SLOT_FORWARD-এর জন্য
কাস্টম বোতাম আছে
|
কাস্টম |
প্লেয়ার কমান্ড
COMMAND_SEEK_TO_NEXT অথবা
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM উপলভ্য।
|
পরবর্তী | |
| কাস্টম বোতাম বা তালিকাভুক্ত কমান্ডের মধ্যে কোনওটিই উপলভ্য নেই। | ফাঁকা | |
| 4 |
মিডিয়া বোতাম
পছন্দ-এ
CommandButton.SLOT_OVERFLOW-এর জন্য কাস্টম বোতাম আছে যা এখনও প্লেস করা হয়নি।
|
কাস্টম |
| 5 |
মিডিয়া বোতাম
পছন্দ-এ
CommandButton.SLOT_OVERFLOW-এর জন্য একটি কাস্টম বোতাম আছে যা এখনও সেট করা হয়নি।
|
কাস্টম |
মিডিয়া বোতাম সংক্রান্ত পছন্দে কাস্টম ওভারফ্লো বোতাম যে ক্রমে যোগ করা হয়েছে, সেই ক্রমেই সেগুলি দেখানো হয়।
কমান্ড বোতাম কাস্টমাইজ করুন
Jetpack Media3-এর মাধ্যমে সিস্টেম মিডিয়া কন্ট্রোল কাস্টমাইজ করতে, আপনি সেশনের মিডিয়া বোতামের পছন্দ এবং কন্ট্রোলারের উপলভ্য কমান্ড সেই অনুযায়ী সেট করতে পারবেন:
MediaSessionতৈরি করুন এবং কাস্টম কমান্ড বোতামের জন্য মিডিয়া বোতামের পছন্দ সংজ্ঞায়িত করুন।MediaSession.Callback.onConnect()-এ,ConnectionResult-এ কাস্টম কমান্ড সহ উপলভ্য কমান্ডগুলি সংজ্ঞায়িত করে কন্ট্রোলারদের অনুমোদন করুন।MediaSession.Callback.onCustomCommand()-এ, ব্যবহারকারীর বেছে নেওয়া কাস্টম কমান্ডের উত্তর দিন।
Kotlin
class PlaybackService : MediaSessionService() { private val customCommandFavorites = SessionCommand(ACTION_FAVORITES, Bundle.EMPTY) private var mediaSession: MediaSession? = null override fun onCreate() { super.onCreate() val favoriteButton = CommandButton.Builder(CommandButton.ICON_HEART_UNFILLED) .setDisplayName("Save to favorites") .setSessionCommand(customCommandFavorites) .build() val player = ExoPlayer.Builder(this).build() // Build the session with a custom layout. mediaSession = MediaSession.Builder(this, player) .setCallback(MyCallback()) .setMediaButtonPreferences(ImmutableList.of(favoriteButton)) .build() } private inner class MyCallback : MediaSession.Callback { override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { // Set available player and session commands. return AcceptedResultBuilder(session) .setAvailableSessionCommands( ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(customCommandFavorites) .build() ) .build() } override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle ): ListenableFuture{ if (customCommand.customAction == ACTION_FAVORITES) { // Do custom logic here saveToFavorites(session.player.currentMediaItem) return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS)) } return super.onCustomCommand(session, controller, customCommand, args) } } }
জাভা
public class PlaybackService extends MediaSessionService { private static final SessionCommand CUSTOM_COMMAND_FAVORITES = new SessionCommand("ACTION_FAVORITES", Bundle.EMPTY); @Nullable private MediaSession mediaSession; public void onCreate() { super.onCreate(); CommandButton favoriteButton = new CommandButton.Builder(CommandButton.ICON_HEART_UNFILLED) .setDisplayName("Save to favorites") .setSessionCommand(CUSTOM_COMMAND_FAVORITES) .build(); Player player = new ExoPlayer.Builder(this).build(); // Build the session with a custom layout. mediaSession = new MediaSession.Builder(this, player) .setCallback(new MyCallback()) .setMediaButtonPreferences(ImmutableList.of(favoriteButton)) .build(); } private static class MyCallback implements MediaSession.Callback { @Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { // Set available player and session commands. return new AcceptedResultBuilder(session) .setAvailableSessionCommands( ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(CUSTOM_COMMAND_FAVORITES) .build()) .build(); } public ListenableFutureonCustomCommand( MediaSession session, MediaSession.ControllerInfo controller, SessionCommand customCommand, Bundle args) { if (customCommand.customAction.equals(CUSTOM_COMMAND_FAVORITES.customAction)) { // Do custom logic here saveToFavorites(session.getPlayer().getCurrentMediaItem()); return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS)); } return MediaSession.Callback.super.onCustomCommand( session, controller, customCommand, args); } } }
আপনার MediaSession কনফিগার করার ব্যাপারে আরও জানতে, যাতে সিস্টেমের মতো ক্লায়েন্ট আপনার মিডিয়া অ্যাপের সাথে কানেক্ট করতে পারে,
অন্যান্য ক্লায়েন্টকে কন্ট্রোল করার অনুমতি দিন দেখুন।
Jetpack Media3-এর মাধ্যমে, আপনি যখন MediaSession প্রয়োগ করেন, তখন আপনার PlaybackState
মিডিয়া প্লেয়ারের সাথে অটোমেটিক আপ-টু-ডেট থাকে। একইভাবে, আপনি যখন
MediaSessionService প্রয়োগ করেন, তখন লাইব্রেরি অটোমেটিক আপনার জন্য
MediaStyle বিজ্ঞপ্তি
প্রকাশ করে এবং এটি আপ-টু-ডেট রাখে।
অ্যাকশন বোতামে উত্তর দেওয়া
ব্যবহারকারী সিস্টেম মিডিয়া কন্ট্রোলে কোনও অ্যাকশন বোতামে ট্যাপ করলে, সিস্টেমের
MediaController আপনার MediaSession-এ প্লেব্যাক কমান্ড পাঠায়। তারপর
MediaSession সেইসব কমান্ড প্লেয়ারকে ডেলিগেট করে। Media3-এর Player
ইন্টারফেসে সংজ্ঞায়িত কমান্ডগুলি মিডিয়া সেশন
অটোমেটিক ম্যানেজ করে।
কাস্টম কমান্ডের উত্তর কীভাবে দিতে হবে সেই বিষয়ে নির্দেশিকা পেতে, কাস্টম কমান্ড যোগ করুন বিকল্প দেখুন।
মিডিয়া আবার চালু করার সুবিধা
মিডিয়া রিজাম্পশন ব্যবহারকারীদের অ্যাপ চালু না করেই ক্যারোজেল থেকে আগের সেশন রিস্টার্ট করার সুবিধা দেয়। প্লেব্যাক শুরু হলে, ব্যবহারকারী মিডিয়া কন্ট্রোলের সাথে স্বাভাবিকভাবে ইন্টার্যাক্ট করেন।
সাউন্ড > মিডিয়া বিকল্পের অধীনে, সেটিংস অ্যাপ ব্যবহার করে প্লেব্যাক আবার শুরু করার ফিচার চালু ও বন্ধ করা যাবে। এছাড়াও, ব্যবহারকারী বড় করা ক্যারোজেলে সোয়াইপ করার পরে দেখানো গিয়ার আইকনে ট্যাপ করে সেটিংস অ্যাক্সেস করতে পারবেন।
Media3, API অফার করে যাতে মিডিয়া রিজুম করার সুবিধা আরও সহজে দেওয়া যায়। এই ফিচার প্রয়োগ করার ব্যাপারে নির্দেশিকা পেতে Media3-এর মাধ্যমে প্লেব্যাক আবার শুরু করা ডকুমেন্টেশন দেখুন।
পুরনো মিডিয়া API ব্যবহার করা
এই বিভাগে ব্যাখ্যা করা হয়েছে যে কীভাবে পুরনো MediaCompat API ব্যবহার করে সিস্টেম মিডিয়া কন্ট্রোলের সাথে ইন্টিগ্রেট করতে হয়।
সিস্টেম MediaSession-এর MediaMetadata থেকে নিম্নলিখিত তথ্য সংগ্রহ করে এবং উপলভ্য হলে তা দেখায়:
METADATA_KEY_ALBUM_ART_URIMETADATA_KEY_TITLEMETADATA_KEY_DISPLAY_TITLEMETADATA_KEY_ARTISTMETADATA_KEY_DURATION(সময়সীমা সেট করা না থাকলে সিক বার প্রগ্রেস দেখায় না)
আপনার কাছে সঠিক ও নির্ভুল মিডিয়া কন্ট্রোল বিজ্ঞপ্তি আছে কিনা তা নিশ্চিত করতে,
বর্তমানে যে মিডিয়া চালানো হচ্ছে তার শিরোনামে METADATA_KEY_TITLE বা METADATA_KEY_DISPLAY_TITLE
মেটাডেটার ভ্যালু সেট করুন।
মিডিয়া প্লেয়ারে বর্তমানে চলা মিডিয়ার অতিবাহিত সময় দেখানো হয়, এর সাথে একটি সিক বার থাকে যা MediaSession
PlaybackState-এর সাথে ম্যাপ করা থাকে।
মিডিয়া প্লেয়ারে বর্তমানে চলা মিডিয়ার প্রগ্রেস দেখা যায়, এর সাথে
একটি সিক বার থাকে যা MediaSession PlaybackState-এর সাথে ম্যাপ করা থাকে। সিক বার
ব্যবহারকারীদের পজিশন পরিবর্তন করতে দেয় এবং মিডিয়া আইটেমের
অতিক্রান্ত সময় দেখায়। সিক বার চালু করতে, আপনাকে অবশ্যই PlaybackState.Builder#setActions প্রয়োগ করতে হবে
এবং ACTION_SEEK_TO অন্তর্ভুক্ত করতে হবে।
| স্লট | অ্যাকশন | নির্ণায়ক |
|---|---|---|
| 1 | চালান |
PlaybackState-এর বর্তমান স্ট্যাটাস নিম্নলিখিতগুলির মধ্যে একটি:
|
| স্পিনার লোড হচ্ছে |
PlaybackState-এর বর্তমান স্ট্যাটাস নিম্নলিখিতগুলির মধ্যে একটি:
|
|
| পজ করুন | PlaybackState-এর বর্তমান স্ট্যাটাস উপরের কোনওটিই নয়। |
|
| 2 | পূর্ববর্তী | PlaybackState অ্যাকশনের মধ্যে ACTION_SKIP_TO_PREVIOUS অন্তর্ভুক্ত। |
| কাস্টম | PlaybackState অ্যাকশনে ACTION_SKIP_TO_PREVIOUS অন্তর্ভুক্ত নেই এবং PlaybackState কাস্টম অ্যাকশনে এমন একটি কাস্টম অ্যাকশন অন্তর্ভুক্ত আছে যা এখনও প্লেস করা হয়নি। |
|
| ফাঁকা | PlaybackState এক্সট্রা-তে SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV কী-এর জন্য true বুলিয়ান ভ্যালু অন্তর্ভুক্ত আছে। |
|
| 3 | পরবর্তী | PlaybackState অ্যাকশনের মধ্যে ACTION_SKIP_TO_NEXT অন্তর্ভুক্ত। |
| কাস্টম | PlaybackState অ্যাকশনে ACTION_SKIP_TO_NEXT অন্তর্ভুক্ত নেই এবং PlaybackState কাস্টম অ্যাকশনে এমন একটি কাস্টম অ্যাকশন অন্তর্ভুক্ত আছে যা এখনও প্লেস করা হয়নি। |
|
| ফাঁকা | PlaybackState এক্সট্রা-তে SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT কী-এর জন্য true বুলিয়ান ভ্যালু অন্তর্ভুক্ত আছে। |
|
| 4 | কাস্টম | PlaybackState কাস্টম অ্যাকশনে এমন একটি কাস্টম অ্যাকশন অন্তর্ভুক্ত আছে যা এখনও প্লেস করা হয়নি। |
| 5 | কাস্টম | PlaybackState কাস্টম অ্যাকশনে এমন একটি কাস্টম অ্যাকশন অন্তর্ভুক্ত আছে যা এখনও প্লেস করা হয়নি। |
স্ট্যান্ডার্ড অ্যাকশন যোগ করুন
নিম্নলিখিত কোডের উদাহরণ থেকে বোঝা যায় যে কীভাবে PlaybackState স্ট্যান্ডার্ড এবং
কাস্টম অ্যাকশন যোগ করতে হয়।
প্লে, পজ, আগের ও পরের মিডিয়া চালানোর জন্য, মিডিয়া সেশনের
PlaybackState-এ এইসব অ্যাকশন সেট করুন।
Kotlin
val session = MediaSessionCompat(context, TAG) val playbackStateBuilder = PlaybackStateCompat.Builder() val style = NotificationCompat.MediaStyle() // For this example, the media is currently paused: val state = PlaybackStateCompat.STATE_PAUSED val position = 0L val playbackSpeed = 1f playbackStateBuilder.setState(state, position, playbackSpeed) // And the user can play, skip to next or previous, and seek val stateActions = PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or PlaybackStateCompat.ACTION_SKIP_TO_NEXT or PlaybackStateCompat.ACTION_SEEK_TO // adding the seek action enables seeking with the seekbar playbackStateBuilder.setActions(stateActions) // ... do more setup here ... session.setPlaybackState(playbackStateBuilder.build()) style.setMediaSession(session.sessionToken) notificationBuilder.setStyle(style)
জাভা
MediaSessionCompat session = new MediaSessionCompat(context, TAG); PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder(); NotificationCompat.MediaStyle style = new NotificationCompat.MediaStyle(); // For this example, the media is currently paused: int state = PlaybackStateCompat.STATE_PAUSED; long position = 0L; float playbackSpeed = 1f; playbackStateBuilder.setState(state, position, playbackSpeed); // And the user can play, skip to next or previous, and seek long stateActions = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SEEK_TO; // adding this enables the seekbar thumb playbackStateBuilder.setActions(stateActions); // ... do more setup here ... session.setPlaybackState(playbackStateBuilder.build()); style.setMediaSession(session.getSessionToken()); notificationBuilder.setStyle(style);
আপনি যদি আগের বা পরের স্লটে কোনও বোতাম না চান, তাহলে
ACTION_SKIP_TO_PREVIOUS বা ACTION_SKIP_TO_NEXT যোগ করবেন না এবং পরিবর্তে সেশনে অতিরিক্ত যোগ করুন:
Kotlin
session.setExtras(Bundle().apply { putBoolean(SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV, true) putBoolean(SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT, true) })
জাভা
Bundle extras = new Bundle(); extras.putBoolean(SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV, true); extras.putBoolean(SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT, true); session.setExtras(extras);
কাস্টম অ্যাকশন যোগ করুন
মিডিয়া কন্ট্রোলে আপনি অন্য যেসব অ্যাকশন দেখাতে চান, তার জন্য আপনি একটি
PlaybackStateCompat.CustomAction
তৈরি করতে এবং তার পরিবর্তে সেটি PlaybackState-এ যোগ করতে পারবেন। এইসব অ্যাকশন যেভাবে যোগ করা হয়েছে সেই
অনুযায়ী দেখানো হয়।
Kotlin
val customAction = PlaybackStateCompat.CustomAction.Builder( "com.example.MY_CUSTOM_ACTION", // action ID "Custom Action", // title - used as content description for the button R.drawable.ic_custom_action ).build() playbackStateBuilder.addCustomAction(customAction)
জাভা
PlaybackStateCompat.CustomAction customAction = new PlaybackStateCompat.CustomAction.Builder( "com.example.MY_CUSTOM_ACTION", // action ID "Custom Action", // title - used as content description for the button R.drawable.ic_custom_action ).build(); playbackStateBuilder.addCustomAction(customAction);
PlaybackState অ্যাকশনে সাড়া দেওয়া হচ্ছে
ব্যবহারকারী কোনও বোতামে ট্যাপ করলে, SystemUI
MediaController.TransportControls
ব্যবহার করে MediaSession-এ কমান্ড পাঠায়। আপনাকে একটি কলব্যাক রেজিস্টার করতে হবে
যা এই ইভেন্টগুলিতে সঠিকভাবে প্রতিক্রিয়া জানাতে পারে।
Kotlin
val callback = object: MediaSession.Callback() { override fun onPlay() { // start playback } override fun onPause() { // pause playback } override fun onSkipToPrevious() { // skip to previous } override fun onSkipToNext() { // skip to next } override fun onSeekTo(pos: Long) { // jump to position in track } override fun onCustomAction(action: String, extras: Bundle?) { when (action) { CUSTOM_ACTION_1 -> doCustomAction1(extras) CUSTOM_ACTION_2 -> doCustomAction2(extras) else -> { Log.w(TAG, "Unknown custom action $action") } } } } session.setCallback(callback)
জাভা
MediaSession.Callback callback = new MediaSession.Callback() { @Override public void onPlay() { // start playback } @Override public void onPause() { // pause playback } @Override public void onSkipToPrevious() { // skip to previous } @Override public void onSkipToNext() { // skip to next } @Override public void onSeekTo(long pos) { // jump to position in track } @Override public void onCustomAction(String action, Bundle extras) { if (action.equals(CUSTOM_ACTION_1)) { doCustomAction1(extras); } else if (action.equals(CUSTOM_ACTION_2)) { doCustomAction2(extras); } else { Log.w(TAG, "Unknown custom action " + action); } } };
মিডিয়া আবার চালু করা
দ্রুত সেটিংসের সেটিংসে আপনার প্লেয়ার অ্যাপ দেখাতে,
আপনাকে অবশ্যই একটি বৈধ MediaSession টোকেন সহ একটি MediaStyle বিজ্ঞপ্তি তৈরি করতে হবে।
MediaStyle বিজ্ঞপ্তির জন্য শীর্ষক দেখাতে, NotificationBuilder.setContentTitle() ব্যবহার করুন।
মিডিয়া প্লেয়ারের জন্য ব্র্যান্ড আইকন দেখাতে, NotificationBuilder.setSmallIcon() ব্যবহার করুন।
প্লেব্যাক আবার চালু করার সুবিধা দিতে, অ্যাপে অবশ্যই MediaBrowserService
এবং MediaSession থাকতে হবে। আপনার MediaSession-এ অবশ্যই onPlay() কলব্যাক প্রয়োগ করতে হবে।
MediaBrowserService প্রয়োগ
ডিভাইস বুট হওয়ার পরে, সিস্টেম সবচেয়ে সম্প্রতি ব্যবহার করা পাঁচটি মিডিয়া অ্যাপ খোঁজে এবং প্রতিটি অ্যাপ থেকে আবার চালানো শুরু করার জন্য কন্ট্রোল প্রদান করে।
SystemUI থেকে কানেকশনের মাধ্যমে সিস্টেম আপনার MediaBrowserService-এর সাথে যোগাযোগ করার চেষ্টা করে। আপনার অ্যাপে এই ধরনের কানেকশনের অনুমতি দিতে হবে, অন্যথায় এটি প্লেব্যাক
আবার চালু করার সুবিধা দিতে পারবে না।
SystemUI থেকে কানেকশন প্যাকেজের নাম
com.android.systemui এবং স্বাক্ষর ব্যবহার করে শনাক্ত ও যাচাই করা যেতে পারে। SystemUI প্ল্যাটফর্মের স্বাক্ষরের সাথে
স্বাক্ষরিত। প্ল্যাটফর্ম সিগনেচারের সাথে কীভাবে চেক করতে হয় তার উদাহরণ
UAMP অ্যাপে দেখতে পাবেন।
প্লেব্যাক আবার চালু করার সুবিধা দিতে, আপনার MediaBrowserService-কে
এইসব আচরণ প্রয়োগ করতে হবে:
onGetRoot()-কে দ্রুত একটি নন-নাল রুট রিটার্ন করতে হবে। অন্যান্য জটিল লজিকonLoadChildren()-এ ম্যানেজ করা উচিতরুট মিডিয়া আইডিতে
onLoadChildren()কল করা হলে, ফলাফলে অবশ্যই একটি FLAG_PLAYABLE চাইল্ড থাকতে হবে।MediaBrowserService-এর উচিত সবচেয়ে সম্প্রতি চালানো মিডিয়া আইটেম ফিরিয়ে দেওয়া যখন তারা একটি EXTRA_RECENT কোয়েরি পায়। ফেরত দেওয়া ভ্যালু জেনেরিক ফাংশনের পরিবর্তে আসল মিডিয়া আইটেম হতে হবে।MediaBrowserService-কে অবশ্যই উপযুক্ত MediaDescription প্রদান করতে হবে, যেখানে title এবং subtitle খালি থাকবে না। এছাড়াও, এটিতে আইকন URI বা আইকন বিটম্যাপ সেট করতে হবে।
নিম্নলিখিত কোডের উদাহরণ থেকে onGetRoot() কীভাবে প্রয়োগ করতে হয় তা দেখানো হয়েছে।
Kotlin
override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints: Bundle? ): BrowserRoot? { ... // Verify that the specified package is SystemUI. You'll need to write your // own logic to do this. if (isSystem(clientPackageName, clientUid)) { rootHints?.let { if (it.getBoolean(BrowserRoot.EXTRA_RECENT)) { // Return a tree with a single playable media item for resumption. val extras = Bundle().apply { putBoolean(BrowserRoot.EXTRA_RECENT, true) } return BrowserRoot(MY_RECENTS_ROOT_ID, extras) } } // You can return your normal tree if the EXTRA_RECENT flag is not present. return BrowserRoot(MY_MEDIA_ROOT_ID, null) } // Return an empty tree to disallow browsing. return BrowserRoot(MY_EMPTY_ROOT_ID, null)
জাভা
@Override public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { ... // Verify that the specified package is SystemUI. You'll need to write your // own logic to do this. if (isSystem(clientPackageName, clientUid)) { if (rootHints != null) { if (rootHints.getBoolean(BrowserRoot.EXTRA_RECENT)) { // Return a tree with a single playable media item for resumption. Bundle extras = new Bundle(); extras.putBoolean(BrowserRoot.EXTRA_RECENT, true); return new BrowserRoot(MY_RECENTS_ROOT_ID, extras); } } // You can return your normal tree if the EXTRA_RECENT flag is not present. return new BrowserRoot(MY_MEDIA_ROOT_ID, null); } // Return an empty tree to disallow browsing. return new BrowserRoot(MY_EMPTY_ROOT_ID, null); }
Android 13-এর আগের ভার্সনের আচরণ
ব্যাকওয়ার্ড কম্প্যাটিবিলিটির জন্য, সিস্টেম UI একটি বিকল্প লেআউট প্রদান করা চালিয়ে যায়
যা Android 13 টার্গেট করার জন্য আপডেট না করা অ্যাপের জন্য বিজ্ঞপ্তি অ্যাকশন ব্যবহার করে,
অথবা যাতে PlaybackState তথ্য অন্তর্ভুক্ত থাকে না। অ্যাকশন বোতামগুলি
MediaStyle বিজ্ঞপ্তির সাথে অ্যাটাচ করা Notification.Action তালিকা থেকে
নেওয়া হয়েছে। সিস্টেম সর্বাধিক পাঁচটি অ্যাকশন দেখায়, যে ক্রমে সেগুলি
যোগ করা হয়েছে। কম্প্যাক্ট মোডে, তিনটি পর্যন্ত বোতাম দেখানো হয়, যা
setShowActionsInCompactView()-এ পাস করা ভ্যালু দ্বারা
নির্ধারিত হয়।
কাস্টম অ্যাকশনগুলি যে ক্রমে PlaybackState-এ যোগ করা হয়েছে সেই ক্রমে রাখা হয়েছে।
MediaStyle বিজ্ঞপ্তিতে কীভাবে অ্যাকশন যোগ করতে হয় তা নিম্নলিখিত কোডের উদাহরণ থেকে জানতে পারবেন :
Kotlin
import androidx.core.app.NotificationCompat import androidx.media3.session.MediaStyleNotificationHelper var notification = NotificationCompat.Builder(context, CHANNEL_ID) // Show controls on lock screen even when user hides sensitive content. .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setSmallIcon(R.drawable.ic_stat_player) // Add media control buttons that invoke intents in your media service .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0 .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) // #1 .addAction(R.drawable.ic_next, "Next", nextPendingIntent) // #2 // Apply the media style template .setStyle(MediaStyleNotificationHelper.MediaStyle(mediaSession) .setShowActionsInCompactView(1 /* #1: pause button */)) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build()
জাভা
import androidx.core.app.NotificationCompat; import androidx.media3.session.MediaStyleNotificationHelper; NotificationCompat.Builder notification = new NotificationCompat.Builder(context, CHANNEL_ID) // Show controls on lock screen even when user hides sensitive content. .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setSmallIcon(R.drawable.ic_stat_player) // Add media control buttons that invoke intents in your media service .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0 .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) // #1 .addAction(R.drawable.ic_next, "Next", nextPendingIntent) // #2 // Apply the media style template .setStyle(new MediaStyleNotificationHelper.MediaStyle(mediaSession) .setShowActionsInCompactView(1 /* #1: pause button */)) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build();