অ্যান্ড্রয়েডে মিডিয়া কন্ট্রোলগুলি কুইক সেটিংসের কাছে অবস্থিত। একাধিক অ্যাপের সেশনগুলি একটি সোয়াইপযোগ্য ক্যারোজেলে সাজানো থাকে। ক্যারোজেলটি এই ক্রমে সেশনগুলি তালিকাভুক্ত করে:
- ফোনে স্থানীয়ভাবে স্ট্রিম বাজছে
- দূরবর্তী স্ট্রিম, যেমন বাহ্যিক ডিভাইস বা কাস্ট সেশনে সনাক্ত করা স্ট্রিম
- পূর্ববর্তী পুনরায় শুরু হওয়া সেশনগুলি, শেষবার যে ক্রমে খেলা হয়েছিল সেই ক্রমে
অ্যান্ড্রয়েড ১৩ (এপিআই লেভেল ৩৩) থেকে শুরু করে, ব্যবহারকারীরা যাতে মিডিয়া প্লে করা অ্যাপগুলির জন্য মিডিয়া কন্ট্রোলের একটি সমৃদ্ধ সেট অ্যাক্সেস করতে পারেন তা নিশ্চিত করার জন্য, মিডিয়া কন্ট্রোলের অ্যাকশন বোতামগুলি Player স্টেট থেকে নেওয়া হয়।
এইভাবে, আপনি বিভিন্ন ডিভাইস জুড়ে মিডিয়া নিয়ন্ত্রণের একটি ধারাবাহিক সেট এবং আরও উন্নত মিডিয়া নিয়ন্ত্রণ অভিজ্ঞতা উপস্থাপন করতে পারেন।
চিত্র ১-এ ফোন এবং ট্যাবলেট ডিভাইসে এটি কেমন দেখায়, তার একটি উদাহরণ দেওয়া হয়েছে।
নিম্নলিখিত টেবিলে বর্ণিত Player স্থিতির উপর ভিত্তি করে সিস্টেমটি পাঁচটি পর্যন্ত অ্যাকশন বোতাম প্রদর্শন করে। কমপ্যাক্ট মোডে, শুধুমাত্র প্রথম তিনটি অ্যাকশন স্লট প্রদর্শিত হয়। এটি অটো, অ্যাসিস্ট্যান্ট এবং ওয়্যার ওএসের মতো অন্যান্য অ্যান্ড্রয়েড প্ল্যাটফর্মগুলিতে মিডিয়া নিয়ন্ত্রণগুলি কীভাবে রেন্ডার করা হয় তার সাথে সামঞ্জস্যপূর্ণ।
| স্লট | মানদণ্ড | অ্যাকশন |
|---|---|---|
| ১ | playWhenReady মিথ্যা অথবা বর্তমান প্লেব্যাক অবস্থা STATE_ENDED । | খেলা |
playWhenReady সত্য এবং বর্তমান প্লেব্যাক অবস্থা হল STATE_BUFFERING । | স্পিনার লোড হচ্ছে | |
playWhenReady সত্য এবং বর্তমান প্লেব্যাক অবস্থা STATE_READY । | বিরতি | |
| ২ | মিডিয়া বোতাম পছন্দগুলিতে CommandButton.SLOT_BACK এর জন্য একটি কাস্টম বোতাম রয়েছে। | কাস্টম |
প্লেয়ার কমান্ড COMMAND_SEEK_TO_PREVIOUS অথবা COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM উপলব্ধ। | পূর্ববর্তী | |
| কোনও কাস্টম বোতাম বা তালিকাভুক্ত কমান্ডগুলির কোনওটিই উপলব্ধ নেই। | খালি | |
| ৩ | মিডিয়া বোতাম পছন্দগুলিতে CommandButton.SLOT_FORWARD এর জন্য একটি কাস্টম বোতাম রয়েছে। | কাস্টম |
প্লেয়ার কমান্ড COMMAND_SEEK_TO_NEXT অথবা COMMAND_SEEK_TO_NEXT_MEDIA_ITEM উপলব্ধ। | পরবর্তী | |
| কোনও কাস্টম বোতাম বা তালিকাভুক্ত কমান্ডগুলির কোনওটিই উপলব্ধ নেই। | খালি | |
| ৪ | মিডিয়া বোতাম পছন্দগুলিতে CommandButton.SLOT_OVERFLOW এর জন্য একটি কাস্টম বোতাম রয়েছে যা এখনও স্থাপন করা হয়নি। | কাস্টম |
| ৫ | মিডিয়া বোতাম পছন্দগুলিতে CommandButton.SLOT_OVERFLOW এর জন্য একটি কাস্টম বোতাম রয়েছে যা এখনও স্থাপন করা হয়নি। | কাস্টম |
কাস্টম ওভারফ্লো বোতামগুলি মিডিয়া বোতাম পছন্দগুলিতে যে ক্রমে যুক্ত করা হয়েছিল সেই ক্রমে স্থাপন করা হয়।
কমান্ড বোতামগুলি কাস্টমাইজ করুন
Jetpack Media3 দিয়ে সিস্টেম মিডিয়া নিয়ন্ত্রণগুলি কাস্টমাইজ করতে, আপনি সেশনের মিডিয়া বোতাম পছন্দ এবং সেই অনুযায়ী কন্ট্রোলারগুলির উপলব্ধ কমান্ডগুলি সেট করতে পারেন:
একটি
MediaSessionতৈরি করুন এবং কাস্টম কমান্ড বোতামগুলির জন্য মিডিয়া বোতাম পছন্দগুলি সংজ্ঞায়িত করুন ।MediaSession.Callback.onConnect()এ,ConnectionResultএ কাস্টম কমান্ড সহ উপলব্ধ কমান্ডগুলি সংজ্ঞায়িত করে কন্ট্রোলারগুলিকে অনুমোদন করুন।MediaSession.Callback.onCustomCommand()তে, ব্যবহারকারীর দ্বারা নির্বাচিত কাস্টম কমান্ডের প্রতিক্রিয়া জানান।
কোটলিন
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 সেই কমান্ডগুলি প্লেয়ারের কাছে অর্পণ করে। মিডিয়া3 এর Player ইন্টারফেসে সংজ্ঞায়িত কমান্ডগুলি স্বয়ংক্রিয়ভাবে মিডিয়া সেশন দ্বারা পরিচালিত হয়।
কাস্টম কমান্ডের প্রতিক্রিয়া জানাতে কীভাবে নির্দেশিকা পেতে হয় তার জন্য কাস্টম কমান্ড যোগ করুন দেখুন।
মিডিয়া পুনঃসূচনা সমর্থন করুন
মিডিয়া রিজিউম ব্যবহারকারীদের অ্যাপটি চালু না করেই ক্যারোজেল থেকে পূর্ববর্তী সেশনগুলি পুনরায় চালু করতে দেয়। প্লেব্যাক শুরু হলে, ব্যবহারকারী স্বাভাবিক উপায়ে মিডিয়া নিয়ন্ত্রণগুলির সাথে যোগাযোগ করে।
প্লেব্যাক পুনঃসূচনা বৈশিষ্ট্যটি সেটিংস অ্যাপ ব্যবহার করে সাউন্ড > মিডিয়া বিকল্পের অধীনে চালু এবং বন্ধ করা যেতে পারে। ব্যবহারকারী প্রসারিত ক্যারোজেলে সোয়াইপ করার পরে প্রদর্শিত গিয়ার আইকনে ট্যাপ করে সেটিংস অ্যাক্সেস করতে পারেন।
মিডিয়া পুনঃসূচনা সমর্থন করা সহজ করার জন্য Media3 API অফার করে। এই বৈশিষ্ট্যটি বাস্তবায়নের নির্দেশিকা জানতে Media3 ডকুমেন্টেশনের সাথে প্লেব্যাক পুনঃসূচনা দেখুন।
লিগ্যাসি মিডিয়া API ব্যবহার করা
এই বিভাগটি ব্যাখ্যা করে যে লিগ্যাসি মিডিয়াকম্প্যাট এপিআই ব্যবহার করে সিস্টেম মিডিয়া নিয়ন্ত্রণের সাথে কীভাবে একীভূত করা যায়।
সিস্টেমটি MediaSession এর MediaMetadata থেকে নিম্নলিখিত তথ্যগুলি পুনরুদ্ধার করে এবং যখন এটি উপলব্ধ থাকে তখন তা প্রদর্শন করে:
-
METADATA_KEY_ALBUM_ART_URI -
METADATA_KEY_TITLE -
METADATA_KEY_DISPLAY_TITLE -
METADATA_KEY_ARTIST -
METADATA_KEY_DURATION(যদি সময়কাল সেট না করা থাকে তবে সিক বার অগ্রগতি দেখায় না)
আপনার কাছে একটি বৈধ এবং নির্ভুল মিডিয়া নিয়ন্ত্রণ বিজ্ঞপ্তি আছে কিনা তা নিশ্চিত করতে, METADATA_KEY_TITLE বা METADATA_KEY_DISPLAY_TITLE মেটাডেটার মান বর্তমানে যে মিডিয়াটি চালানো হচ্ছে তার শিরোনামে সেট করুন।
মিডিয়া প্লেয়ারটি বর্তমানে চলমান মিডিয়ার জন্য অতিবাহিত সময় দেখায়, সাথে একটি seek বারও দেখায় যা MediaSession PlaybackState এ ম্যাপ করা হয়।
মিডিয়া প্লেয়ারটি বর্তমানে চলমান মিডিয়ার অগ্রগতি দেখায়, সাথে একটি seek বারও থাকে যা MediaSession PlaybackState সাথে ম্যাপ করা থাকে। seek বার ব্যবহারকারীদের অবস্থান পরিবর্তন করতে দেয় এবং মিডিয়া আইটেমের জন্য অতিবাহিত সময় প্রদর্শন করে। seek বারটি সক্রিয় করার জন্য, আপনাকে PlaybackState.Builder#setActions প্রয়োগ করতে হবে এবং ACTION_SEEK_TO অন্তর্ভুক্ত করতে হবে।
| স্লট | অ্যাকশন | মানদণ্ড |
|---|---|---|
| ১ | খেলা | PlaybackState বর্তমান অবস্থা নিম্নলিখিতগুলির মধ্যে একটি:
|
| স্পিনার লোড হচ্ছে | PlaybackState বর্তমান অবস্থা নিম্নলিখিতগুলির মধ্যে একটি:
| |
| বিরতি | PlaybackState বর্তমান অবস্থা উপরের কোনটিই নয়। | |
| ২ | পূর্ববর্তী | PlaybackState অ্যাকশনের মধ্যে ACTION_SKIP_TO_PREVIOUS অন্তর্ভুক্ত। |
| কাস্টম | PlaybackState অ্যাকশনে ACTION_SKIP_TO_PREVIOUS অন্তর্ভুক্ত থাকে না এবং PlaybackState কাস্টম অ্যাকশনে এমন একটি কাস্টম অ্যাকশন অন্তর্ভুক্ত থাকে যা এখনও স্থাপন করা হয়নি। | |
| খালি | PlaybackState অতিরিক্তগুলিতে SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV কী-এর জন্য একটি true বুলিয়ান মান অন্তর্ভুক্ত থাকে। | |
| ৩ | পরবর্তী | PlaybackState অ্যাকশনের মধ্যে ACTION_SKIP_TO_NEXT অন্তর্ভুক্ত থাকে। |
| কাস্টম | PlaybackState অ্যাকশনে ACTION_SKIP_TO_NEXT অন্তর্ভুক্ত থাকে না এবং PlaybackState কাস্টম অ্যাকশনে এমন একটি কাস্টম অ্যাকশন অন্তর্ভুক্ত থাকে যা এখনও স্থাপন করা হয়নি। | |
| খালি | PlaybackState অতিরিক্তগুলিতে SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT এর জন্য একটি true বুলিয়ান মান অন্তর্ভুক্ত থাকে। | |
| ৪ | কাস্টম | PlaybackState কাস্টম অ্যাকশনের মধ্যে এমন একটি কাস্টম অ্যাকশন অন্তর্ভুক্ত থাকে যা এখনও স্থাপন করা হয়নি। |
| ৫ | কাস্টম | PlaybackState কাস্টম অ্যাকশনের মধ্যে এমন একটি কাস্টম অ্যাকশন অন্তর্ভুক্ত থাকে যা এখনও স্থাপন করা হয়নি। |
স্ট্যান্ডার্ড অ্যাকশন যোগ করুন
নিম্নলিখিত কোড উদাহরণগুলি PlaybackState স্ট্যান্ডার্ড এবং কাস্টম অ্যাকশনগুলি কীভাবে যুক্ত করতে হয় তা ব্যাখ্যা করে।
প্লে, পজ, প্রিয় এবং নেক্সট এর জন্য, মিডিয়া সেশনের জন্য PlaybackState এই অ্যাকশনগুলি সেট করুন।
কোটলিন
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 যোগ করবেন না, বরং সেশনে অতিরিক্ত যোগ করুন:
কোটলিন
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 এ যোগ করতে পারেন। এই অ্যাকশনগুলি যে ক্রমে যোগ করা হয়েছিল সেই ক্রমে দেখানো হয়েছে।
কোটলিন
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);
প্লেব্যাকস্টেট অ্যাকশনের প্রতিক্রিয়া জানানো
যখন একজন ব্যবহারকারী একটি বোতামে ট্যাপ করেন, তখন SystemUI MediaController.TransportControls ব্যবহার করে MediaSession এ একটি কমান্ড ফেরত পাঠায়। আপনাকে একটি কলব্যাক নিবন্ধন করতে হবে যা এই ইভেন্টগুলিতে সঠিকভাবে প্রতিক্রিয়া জানাতে পারে।
কোটলিন
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 সাথে যোগাযোগ করার চেষ্টা করে। আপনার অ্যাপকে অবশ্যই এই ধরনের সংযোগের অনুমতি দিতে হবে, অন্যথায় এটি প্লেব্যাক পুনঃসূচনা সমর্থন করতে পারবে না।
প্যাকেজ নাম com.android.systemui এবং স্বাক্ষর ব্যবহার করে SystemUI থেকে সংযোগগুলি সনাক্ত এবং যাচাই করা যেতে পারে। SystemUI প্ল্যাটফর্ম স্বাক্ষর দিয়ে স্বাক্ষরিত হয়। প্ল্যাটফর্ম স্বাক্ষরের সাথে কীভাবে পরীক্ষা করবেন তার একটি উদাহরণ UAMP অ্যাপে পাওয়া যাবে।
প্লেব্যাক পুনঃসূচনা সমর্থন করার জন্য, আপনার MediaBrowserService অবশ্যই এই আচরণগুলি বাস্তবায়ন করতে হবে:
onGetRoot()অবশ্যই একটি নন-নাল রুট দ্রুত ফেরত দিতে হবে। অন্যান্য জটিল লজিকগুলিonLoadChildren()তে পরিচালনা করা উচিত।যখন রুট মিডিয়া আইডিতে
onLoadChildren()কল করা হয়, তখন ফলাফলে একটি FLAG_PLAYABLE চাইল্ড থাকতে হবে।MediaBrowserServiceযখন একটি EXTRA_RECENT কোয়েরি পাবে তখন তাদের সবচেয়ে সাম্প্রতিক প্লে করা মিডিয়া আইটেমটি ফেরত পাঠানো উচিত। ফেরত দেওয়া মানটি জেনেরিক ফাংশনের পরিবর্তে একটি প্রকৃত মিডিয়া আইটেম হওয়া উচিত।MediaBrowserServiceঅবশ্যই একটি উপযুক্ত MediaDescription প্রদান করতে হবে যার শিরোনাম এবং সাবটাইটেল খালি থাকবে না। এটি একটি আইকন URI অথবা একটি আইকন বিটম্যাপও সেট করবে।
নিম্নলিখিত কোড উদাহরণগুলি onGetRoot() কীভাবে বাস্তবায়ন করতে হয় তা ব্যাখ্যা করে।
কোটলিন
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); }
অ্যান্ড্রয়েড ১৩-এর আগেকার আচরণ
ব্যাকওয়ার্ড সামঞ্জস্যের জন্য, সিস্টেম UI একটি বিকল্প লেআউট প্রদান করে যা এমন অ্যাপগুলির জন্য বিজ্ঞপ্তি ক্রিয়া ব্যবহার করে যা Android 13 টার্গেট করার জন্য আপডেট হয় না, অথবা যেগুলিতে PlaybackState তথ্য অন্তর্ভুক্ত থাকে না। অ্যাকশন বোতামগুলি MediaStyle বিজ্ঞপ্তির সাথে সংযুক্ত Notification.Action তালিকা থেকে নেওয়া হয়। সিস্টেমটি যে ক্রমে যোগ করা হয়েছিল সেই ক্রমে পাঁচটি পর্যন্ত ক্রিয়া প্রদর্শন করে। কমপ্যাক্ট মোডে, setShowActionsInCompactView() এ পাস করা মান দ্বারা নির্ধারিত তিনটি পর্যন্ত বোতাম প্রদর্শিত হয়।
কাস্টম অ্যাকশনগুলি PlaybackState এ যে ক্রমে যোগ করা হয়েছিল সেই ক্রমে স্থাপন করা হয়।
নিম্নলিখিত কোড উদাহরণটি মিডিয়াস্টাইল বিজ্ঞপ্তিতে কীভাবে অ্যাকশন যুক্ত করতে হয় তা ব্যাখ্যা করে:
কোটলিন
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();