অ্যান্ড্রয়েডের মিডিয়া নিয়ন্ত্রণগুলি দ্রুত সেটিংসের কাছে অবস্থিত৷ একাধিক অ্যাপের সেশন একটি সোয়াইপযোগ্য ক্যারোজেলে সাজানো হয়েছে। ক্যারোজেল এই ক্রমে সেশন তালিকাভুক্ত করে:
- স্ট্রিমগুলি ফোনে স্থানীয়ভাবে বাজছে৷
- দূরবর্তী স্ট্রীম, যেমন বহিরাগত ডিভাইস বা কাস্ট সেশনে সনাক্ত করা হয়
- পূর্ববর্তী পুনঃসূচনাযোগ্য সেশন, যে ক্রমে সেগুলি শেষ খেলা হয়েছিল
অ্যান্ড্রয়েড 13 (API লেভেল 33) থেকে শুরু করে, ব্যবহারকারীরা যাতে মিডিয়া প্লে করা অ্যাপগুলির জন্য মিডিয়া কন্ট্রোলের একটি সমৃদ্ধ সেট অ্যাক্সেস করতে পারে তা নিশ্চিত করতে, মিডিয়া কন্ট্রোলের অ্যাকশন বোতামগুলি Player
স্টেট থেকে নেওয়া হয়েছে।
এইভাবে, আপনি মিডিয়া নিয়ন্ত্রণের একটি সামঞ্জস্যপূর্ণ সেট এবং ডিভাইস জুড়ে আরও পালিশ মিডিয়া নিয়ন্ত্রণের অভিজ্ঞতা উপস্থাপন করতে পারেন।
চিত্র 1 যথাক্রমে একটি ফোন এবং ট্যাবলেট ডিভাইসে এটি কীভাবে দেখায় তার একটি উদাহরণ দেখায়।
নিম্নলিখিত টেবিলে বর্ণিত Player
অবস্থার উপর ভিত্তি করে সিস্টেমটি পাঁচটি পর্যন্ত অ্যাকশন বোতাম প্রদর্শন করে। কমপ্যাক্ট মোডে, শুধুমাত্র প্রথম তিনটি অ্যাকশন স্লট প্রদর্শিত হয়। এটি অটো, অ্যাসিস্ট্যান্ট এবং Wear OS-এর মতো অন্যান্য Android প্ল্যাটফর্মগুলিতে মিডিয়া নিয়ন্ত্রণগুলি কীভাবে রেন্ডার করা হয় তার সাথে সারিবদ্ধ করে।
স্লট | মানদণ্ড | অ্যাকশন |
---|---|---|
1 | playWhenReady মিথ্যা বা বর্তমান প্লেব্যাক অবস্থা STATE_ENDED । | খেলা |
playWhenReady সত্য এবং বর্তমান প্লেব্যাকের অবস্থা হল STATE_BUFFERING ৷ | স্পিনার লোড হচ্ছে | |
playWhenReady সত্য এবং বর্তমান প্লেব্যাক অবস্থা STATE_READY । | বিরতি | |
2 | প্লেয়ার কমান্ড COMMAND_SEEK_TO_PREVIOUS বা COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM উপলব্ধ৷ | আগের |
কোন প্লেয়ার কমান্ড COMMAND_SEEK_TO_PREVIOUS বা COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM উপলব্ধ নেই, এবং কাস্টম লেআউট থেকে একটি কাস্টম কমান্ড যা এখনও স্থাপন করা হয়নি স্লটটি পূরণ করার জন্য উপলব্ধ৷ | কাস্টম | |
EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV কী-এর জন্য সেশন অতিরিক্তগুলি একটি true বুলিয়ান মান অন্তর্ভুক্ত করে। | খালি | |
3 | প্লেয়ার কমান্ড COMMAND_SEEK_TO_NEXT বা COMMAND_SEEK_TO_NEXT_MEDIA_ITEM উপলব্ধ৷ | পরবর্তী |
কোন প্লেয়ার কমান্ড COMMAND_SEEK_TO_NEXT বা COMMAND_SEEK_TO_NEXT_MEDIA_ITEM উপলব্ধ নেই, এবং কাস্টম লেআউট থেকে একটি কাস্টম কমান্ড যা এখনও স্থাপন করা হয়নি স্লটটি পূরণ করার জন্য উপলব্ধ৷ | কাস্টম | |
EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT কী-এর জন্য সেশন অতিরিক্তগুলি একটি true বুলিয়ান মান অন্তর্ভুক্ত করে। | খালি | |
4 | কাস্টম লেআউট থেকে একটি কাস্টম কমান্ড যা এখনও স্থাপন করা হয়নি স্লটটি পূরণ করার জন্য উপলব্ধ। | কাস্টম |
5 | কাস্টম লেআউট থেকে একটি কাস্টম কমান্ড যা এখনও স্থাপন করা হয়নি স্লটটি পূরণ করার জন্য উপলব্ধ। | কাস্টম |
কাস্টম কমান্ডগুলি কাস্টম লেআউটে যে ক্রমে যুক্ত করা হয়েছিল সেই ক্রমে স্থাপন করা হয়।
কমান্ড বোতাম কাস্টমাইজ করুন
Jetpack Media3 এর সাথে সিস্টেম মিডিয়া কন্ট্রোল কাস্টমাইজ করতে, আপনি সেশনের কাস্টম লেআউট এবং সেই অনুযায়ী কন্ট্রোলারের উপলব্ধ কমান্ড সেট করতে পারেন, যখন একটি MediaSessionService
প্রয়োগ করা হয় :
onCreate()
এ, একটি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() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(customCommandFavorites) .build() val player = ExoPlayer.Builder(this).build() // Build the session with a custom layout. mediaSession = MediaSession.Builder(this, player) .setCallback(MyCallback()) .setCustomLayout(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) .setAvailablePlayerCommands( ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .build() ) .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() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .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()) .setCustomLayout(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) .setAvailablePlayerCommands( ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .build()) .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
ইন্টারফেসে সংজ্ঞায়িত কমান্ডগুলি মিডিয়া সেশন দ্বারা স্বয়ংক্রিয়ভাবে পরিচালনা করা হয়।
একটি কাস্টম কমান্ডে কীভাবে প্রতিক্রিয়া জানাতে হয় তার নির্দেশনার জন্য কাস্টম কমান্ড যুক্ত করুন দেখুন।
প্রি-অ্যান্ড্রয়েড 13 আচরণ
পশ্চাদগামী সামঞ্জস্যের জন্য, সিস্টেম UI একটি বিকল্প লেআউট প্রদান করে যা অ্যাপ্লিকেশানগুলির জন্য বিজ্ঞপ্তি অ্যাকশন ব্যবহার করে যেগুলি Android 13 টার্গেট করার জন্য আপডেট হয় না, বা যেগুলি PlaybackState
তথ্য অন্তর্ভুক্ত করে না। অ্যাকশন বোতামগুলি MediaStyle
বিজ্ঞপ্তির সাথে সংযুক্ত Notification.Action
তালিকা থেকে প্রাপ্ত। যে ক্রমানুসারে সেগুলি যোগ করা হয়েছিল সেই ক্রমে সিস্টেমটি পাঁচটি পর্যন্ত ক্রিয়া প্রদর্শন করে৷ কমপ্যাক্ট মোডে, তিনটি পর্যন্ত বোতাম দেখানো হয়, setShowActionsInCompactView()
এ পাস করা মান দ্বারা নির্ধারিত হয়।
কাস্টম অ্যাকশনগুলি PlaybackState
-এ যে ক্রমে যুক্ত করা হয়েছিল সেই ক্রমে স্থাপন করা হয়৷
নিম্নলিখিত কোড উদাহরণটি ব্যাখ্যা করে কিভাবে MediaStyle বিজ্ঞপ্তিতে অ্যাকশন যোগ করতে হয়:
কোটলিন
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) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setSmallIcon(R.drawable.ic_stat_player) .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) .addAction(R.drawable.ic_next, "Next", nextPendingIntent) .setStyle(new MediaStyleNotificationHelper.MediaStyle(mediaSession) .setShowActionsInCompactView(1 /* #1: pause button */)) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build();
মিডিয়া পুনঃসূচনা সমর্থন
মিডিয়া পুনঃসূচনা ব্যবহারকারীদের অ্যাপটি শুরু না করেই ক্যারোজেল থেকে আগের সেশনগুলি পুনরায় চালু করতে দেয়। প্লেব্যাক শুরু হলে, ব্যবহারকারী মিডিয়া নিয়ন্ত্রণের সাথে স্বাভাবিক উপায়ে যোগাযোগ করে।
প্লেব্যাক পুনঃসূচনা বৈশিষ্ট্যটি সাউন্ড > মিডিয়া বিকল্পের অধীনে সেটিংস অ্যাপ ব্যবহার করে চালু এবং বন্ধ করা যেতে পারে। ব্যবহারকারী প্রসারিত ক্যারোজেলে সোয়াইপ করার পরে প্রদর্শিত গিয়ার আইকনে ট্যাপ করে সেটিংস অ্যাক্সেস করতে পারেন।
মিডিয়া পুনরুদ্ধার সমর্থন করা সহজ করার জন্য Media3 APIs অফার করে। এই বৈশিষ্ট্যটি বাস্তবায়নের নির্দেশনার জন্য Media3 ডকুমেন্টেশন সহ প্লেব্যাক পুনঃসূচনা দেখুন।
লিগ্যাসি মিডিয়া API ব্যবহার করে
এই বিভাগটি ব্যাখ্যা করে কিভাবে লিগ্যাসি MediaCompat 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
মেটাডেটার মান বর্তমানে প্লে করা মিডিয়ার শিরোনামে সেট করুন৷
মিডিয়া প্লেয়ার বর্তমানে বাজানো মিডিয়ার জন্য অতিবাহিত সময় দেখায়, সাথে একটি সিক বার যা 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
এই ক্রিয়াগুলি সেট করুন৷
কোটলিন
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);
প্লেব্যাকস্টেট অ্যাকশনের প্রতিক্রিয়া
যখন একজন ব্যবহারকারী একটি বোতামে ট্যাপ করে, তখন MediaSession
এ একটি কমান্ড ফেরত পাঠাতে SystemUI MediaController.TransportControls
ব্যবহার করে। আপনাকে একটি কলব্যাক নিবন্ধন করতে হবে যা এই ইভেন্টগুলিতে সঠিকভাবে প্রতিক্রিয়া জানাতে পারে।
কোটলিন
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 প্রদান করতে হবে৷ এটি একটি আইকন 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); }
অ্যান্ড্রয়েডের মিডিয়া নিয়ন্ত্রণগুলি দ্রুত সেটিংসের কাছে অবস্থিত৷ একাধিক অ্যাপের সেশন একটি সোয়াইপযোগ্য ক্যারোজেলে সাজানো হয়েছে। ক্যারোজেল এই ক্রমে সেশন তালিকাভুক্ত করে:
- স্ট্রিমগুলি ফোনে স্থানীয়ভাবে বাজছে৷
- দূরবর্তী স্ট্রীম, যেমন বহিরাগত ডিভাইস বা কাস্ট সেশনে সনাক্ত করা হয়
- পূর্ববর্তী পুনঃসূচনাযোগ্য সেশন, যে ক্রমে সেগুলি শেষ খেলা হয়েছিল
অ্যান্ড্রয়েড 13 (API লেভেল 33) থেকে শুরু করে, ব্যবহারকারীরা যাতে মিডিয়া প্লে করা অ্যাপগুলির জন্য মিডিয়া কন্ট্রোলের একটি সমৃদ্ধ সেট অ্যাক্সেস করতে পারে তা নিশ্চিত করতে, মিডিয়া কন্ট্রোলের অ্যাকশন বোতামগুলি Player
স্টেট থেকে নেওয়া হয়েছে।
এইভাবে, আপনি মিডিয়া নিয়ন্ত্রণের একটি সামঞ্জস্যপূর্ণ সেট এবং ডিভাইস জুড়ে আরও পালিশ মিডিয়া নিয়ন্ত্রণের অভিজ্ঞতা উপস্থাপন করতে পারেন।
চিত্র 1 যথাক্রমে একটি ফোন এবং ট্যাবলেট ডিভাইসে এটি কীভাবে দেখায় তার একটি উদাহরণ দেখায়।
নিম্নলিখিত টেবিলে বর্ণিত Player
অবস্থার উপর ভিত্তি করে সিস্টেমটি পাঁচটি পর্যন্ত অ্যাকশন বোতাম প্রদর্শন করে। কমপ্যাক্ট মোডে, শুধুমাত্র প্রথম তিনটি অ্যাকশন স্লট প্রদর্শিত হয়। এটি অটো, অ্যাসিস্ট্যান্ট এবং Wear OS-এর মতো অন্যান্য Android প্ল্যাটফর্মগুলিতে মিডিয়া নিয়ন্ত্রণগুলি কীভাবে রেন্ডার করা হয় তার সাথে সারিবদ্ধ করে।
স্লট | মানদণ্ড | অ্যাকশন |
---|---|---|
1 | playWhenReady মিথ্যা বা বর্তমান প্লেব্যাক অবস্থা STATE_ENDED । | খেলা |
playWhenReady সত্য এবং বর্তমান প্লেব্যাকের অবস্থা হল STATE_BUFFERING ৷ | স্পিনার লোড হচ্ছে | |
playWhenReady সত্য এবং বর্তমান প্লেব্যাক অবস্থা STATE_READY । | বিরতি | |
2 | প্লেয়ার কমান্ড COMMAND_SEEK_TO_PREVIOUS বা COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM উপলব্ধ৷ | আগের |
কোন প্লেয়ার কমান্ড COMMAND_SEEK_TO_PREVIOUS বা COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM উপলব্ধ নেই, এবং কাস্টম লেআউট থেকে একটি কাস্টম কমান্ড যা এখনও স্থাপন করা হয়নি স্লটটি পূরণ করার জন্য উপলব্ধ৷ | কাস্টম | |
EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV কী-এর জন্য সেশন অতিরিক্তগুলি একটি true বুলিয়ান মান অন্তর্ভুক্ত করে। | খালি | |
3 | প্লেয়ার কমান্ড COMMAND_SEEK_TO_NEXT বা COMMAND_SEEK_TO_NEXT_MEDIA_ITEM উপলব্ধ৷ | পরবর্তী |
কোন প্লেয়ার কমান্ড COMMAND_SEEK_TO_NEXT বা COMMAND_SEEK_TO_NEXT_MEDIA_ITEM উপলব্ধ নেই, এবং কাস্টম লেআউট থেকে একটি কাস্টম কমান্ড যা এখনও স্থাপন করা হয়নি স্লটটি পূরণ করার জন্য উপলব্ধ৷ | কাস্টম | |
EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT কী-এর জন্য সেশন অতিরিক্তগুলি একটি true বুলিয়ান মান অন্তর্ভুক্ত করে। | খালি | |
4 | কাস্টম লেআউট থেকে একটি কাস্টম কমান্ড যা এখনও স্থাপন করা হয়নি স্লটটি পূরণ করার জন্য উপলব্ধ। | কাস্টম |
5 | কাস্টম লেআউট থেকে একটি কাস্টম কমান্ড যা এখনও স্থাপন করা হয়নি স্লটটি পূরণ করার জন্য উপলব্ধ। | কাস্টম |
কাস্টম কমান্ডগুলি কাস্টম লেআউটে যে ক্রমে যুক্ত করা হয়েছিল সেই ক্রমে স্থাপন করা হয়।
কমান্ড বোতাম কাস্টমাইজ করুন
Jetpack Media3 এর সাথে সিস্টেম মিডিয়া কন্ট্রোল কাস্টমাইজ করতে, আপনি সেশনের কাস্টম লেআউট এবং সেই অনুযায়ী কন্ট্রোলারের উপলব্ধ কমান্ড সেট করতে পারেন, যখন একটি MediaSessionService
প্রয়োগ করা হয় :
onCreate()
এ, একটি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() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(customCommandFavorites) .build() val player = ExoPlayer.Builder(this).build() // Build the session with a custom layout. mediaSession = MediaSession.Builder(this, player) .setCallback(MyCallback()) .setCustomLayout(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) .setAvailablePlayerCommands( ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .build() ) .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() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .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()) .setCustomLayout(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) .setAvailablePlayerCommands( ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .build()) .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
ইন্টারফেসে সংজ্ঞায়িত কমান্ডগুলি মিডিয়া সেশন দ্বারা স্বয়ংক্রিয়ভাবে পরিচালনা করা হয়।
একটি কাস্টম কমান্ডে কীভাবে প্রতিক্রিয়া জানাতে হয় তার নির্দেশনার জন্য কাস্টম কমান্ড যুক্ত করুন দেখুন।
প্রি-অ্যান্ড্রয়েড 13 আচরণ
পশ্চাদগামী সামঞ্জস্যের জন্য, সিস্টেম UI একটি বিকল্প লেআউট প্রদান করে যা অ্যাপ্লিকেশানগুলির জন্য বিজ্ঞপ্তি অ্যাকশন ব্যবহার করে যেগুলি Android 13 টার্গেট করার জন্য আপডেট হয় না, বা যেগুলি PlaybackState
তথ্য অন্তর্ভুক্ত করে না। অ্যাকশন বোতামগুলি MediaStyle
বিজ্ঞপ্তির সাথে সংযুক্ত Notification.Action
তালিকা থেকে প্রাপ্ত। যে ক্রমানুসারে সেগুলি যোগ করা হয়েছিল সেই ক্রমে সিস্টেমটি পাঁচটি পর্যন্ত ক্রিয়া প্রদর্শন করে৷ কমপ্যাক্ট মোডে, তিনটি পর্যন্ত বোতাম দেখানো হয়, setShowActionsInCompactView()
এ পাস করা মান দ্বারা নির্ধারিত হয়।
কাস্টম অ্যাকশনগুলি PlaybackState
-এ যে ক্রমে যুক্ত করা হয়েছিল সেই ক্রমে স্থাপন করা হয়৷
নিম্নলিখিত কোড উদাহরণটি ব্যাখ্যা করে কিভাবে MediaStyle বিজ্ঞপ্তিতে অ্যাকশন যোগ করতে হয়:
কোটলিন
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) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setSmallIcon(R.drawable.ic_stat_player) .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) .addAction(R.drawable.ic_next, "Next", nextPendingIntent) .setStyle(new MediaStyleNotificationHelper.MediaStyle(mediaSession) .setShowActionsInCompactView(1 /* #1: pause button */)) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build();
মিডিয়া পুনঃসূচনা সমর্থন
মিডিয়া পুনঃসূচনা ব্যবহারকারীদের অ্যাপটি শুরু না করেই ক্যারোজেল থেকে আগের সেশনগুলি পুনরায় চালু করতে দেয়। প্লেব্যাক শুরু হলে, ব্যবহারকারী মিডিয়া নিয়ন্ত্রণের সাথে স্বাভাবিক উপায়ে যোগাযোগ করে।
প্লেব্যাক পুনঃসূচনা বৈশিষ্ট্যটি সাউন্ড > মিডিয়া বিকল্পের অধীনে সেটিংস অ্যাপ ব্যবহার করে চালু এবং বন্ধ করা যেতে পারে। ব্যবহারকারী প্রসারিত ক্যারোজেলে সোয়াইপ করার পরে প্রদর্শিত গিয়ার আইকনে ট্যাপ করে সেটিংস অ্যাক্সেস করতে পারেন।
মিডিয়া পুনরুদ্ধার সমর্থন করা সহজ করার জন্য Media3 APIs অফার করে। এই বৈশিষ্ট্যটি বাস্তবায়নের নির্দেশনার জন্য Media3 ডকুমেন্টেশন সহ প্লেব্যাক পুনঃসূচনা দেখুন।
লিগ্যাসি মিডিয়া API ব্যবহার করে
এই বিভাগটি ব্যাখ্যা করে কিভাবে লিগ্যাসি MediaCompat 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
মেটাডেটার মান বর্তমানে প্লে করা মিডিয়ার শিরোনামে সেট করুন৷
মিডিয়া প্লেয়ার বর্তমানে বাজানো মিডিয়ার জন্য অতিবাহিত সময় দেখায়, সাথে একটি সিক বার যা 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
এই ক্রিয়াগুলি সেট করুন৷
কোটলিন
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);
প্লেব্যাকস্টেট অ্যাকশনের প্রতিক্রিয়া
যখন একজন ব্যবহারকারী একটি বোতামে ট্যাপ করে, তখন MediaSession
এ একটি কমান্ড ফেরত পাঠাতে SystemUI MediaController.TransportControls
ব্যবহার করে। আপনাকে একটি কলব্যাক নিবন্ধন করতে হবে যা এই ইভেন্টগুলিতে সঠিকভাবে প্রতিক্রিয়া জানাতে পারে।
কোটলিন
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 প্রদান করতে হবে৷ এটি একটি আইকন 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); }