मीडिया कंट्रोल

Android में मीडिया कंट्रोल, क्विक सेटिंग के आस-पास होते हैं. एक से ज़्यादा ऐप्लिकेशन के सेशन, स्वाइप किए जा सकने वाले कैरसेल में व्यवस्थित किए जाते हैं. कैरसेल में सेशन इस क्रम में दिखते हैं:

  • फ़ोन पर चल रही स्ट्रीम
  • रिमोट स्ट्रीम, जैसे कि बाहरी डिवाइसों या कास्ट सेशन पर मिली स्ट्रीम
  • फिर से शुरू किए जा सकने वाले पिछले सेशन, उसी क्रम में जिनमें उन्हें आखिरी बार चलाया गया था

Android 13 (एपीआई लेवल 33) से, मीडिया कंट्रोल पर मौजूद ऐक्शन बटन को Player स्टेटस से लिया जाता है. इससे यह पक्का किया जा सकता है कि उपयोगकर्ता, मीडिया चलाने वाले ऐप्लिकेशन के लिए मीडिया कंट्रोल का बेहतर सेट ऐक्सेस कर पाएं.

इस तरह, सभी डिवाइसों पर मीडिया कंट्रोल का एक जैसा सेट और बेहतर मीडिया कंट्रोल अनुभव दिया जा सकता है.

फ़ोटो 1 में, यह दिखाया गया है कि यह फ़ोन और टैबलेट डिवाइस पर कैसा दिखता है.

फ़ोन और टैबलेट डिवाइसों पर मीडिया कंट्रोल कैसे दिखते हैं. इसके लिए, सैंपल ट्रैक का उदाहरण दिया गया है, जिसमें बटन कैसे दिख सकते हैं
पहली इमेज: फ़ोन और टैबलेट डिवाइसों पर मीडिया कंट्रोल

सिस्टम, Player की स्थिति के आधार पर ज़्यादा से ज़्यादा पांच ऐक्शन बटन दिखाता है. इनके बारे में नीचे दी गई टेबल में बताया गया है. कॉम्पैक्ट मोड में, सिर्फ़ पहले तीन ऐक्शन स्लॉट दिखाए जाते हैं. यह उसी तरह से काम करता है जिस तरह Auto, Assistant, और 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 लागू करते समय, सेशन का कस्टम लेआउट और कंट्रोलर के उपलब्ध निर्देशों को सेट किया जा सकता है:

  1. onCreate() में, MediaSession बनाएं और कमांड बटन का कस्टम लेआउट तय करें.

  2. MediaSession.Callback.onConnect() में, ConnectionResult में उपलब्ध कमांड तय करके, कंट्रोलर को अनुमति दें. इनमें कस्टम कमांड भी शामिल हैं.

  3. 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()
        .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)
    }
  }
}

Java

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 ListenableFuture onCustomCommand(
        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 इंटरफ़ेस में तय किए गए निर्देश, मीडिया सेशन में अपने-आप लागू हो जाते हैं.

कस्टम निर्देश का जवाब देने के तरीके के बारे में जानने के लिए, कस्टम निर्देश जोड़ना देखें.

Android 13 से पहले का व्यवहार

पुराने वर्शन के साथ काम करने के लिए, System 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()

Java

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, मीडिया को फिर से चलाने की सुविधा को आसान बनाने के लिए एपीआई उपलब्ध कराता है. इस सुविधा को लागू करने के बारे में दिशा-निर्देश पाने के लिए, Media3 की मदद से प्लेबैक फिर से शुरू करना दस्तावेज़ देखें.

लेगसी मीडिया एपीआई का इस्तेमाल करना

इस सेक्शन में, लेगसी 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 की मौजूदा स्थिति इनमें से कोई एक है:
  • STATE_NONE
  • STATE_STOPPED
  • STATE_PAUSED
  • STATE_ERROR
लोडिंग स्पिनर PlaybackState की मौजूदा स्थिति इनमें से कोई एक है:
  • STATE_CONNECTING
  • STATE_BUFFERING
रोकें PlaybackState की मौजूदा स्थिति, इनमें से कोई नहीं है.
2 पीछे जाएं PlaybackState कार्रवाइयों में ACTION_SKIP_TO_PREVIOUS शामिल है.
पसंद के मुताबिक़ PlaybackState कार्रवाइयों में ACTION_SKIP_TO_PREVIOUS शामिल नहीं है और PlaybackState कस्टम ऐक्शन में एक ऐसा कस्टम ऐक्शन शामिल है जिसे अब तक नहीं डाला गया है.
कोई भी तार नहीं लगा है PlaybackState extras में, बटन SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV के लिए true बूलियन वैल्यू शामिल होती है.
3 अगला PlaybackState कार्रवाइयों में ACTION_SKIP_TO_NEXT शामिल है.
पसंद के मुताबिक़ PlaybackState कार्रवाइयों में ACTION_SKIP_TO_NEXT शामिल नहीं है और PlaybackState कस्टम ऐक्शन में एक ऐसा कस्टम ऐक्शन शामिल है जिसे अब तक नहीं डाला गया है.
कोई भी तार नहीं लगा है PlaybackState extras में, बटन 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)

Java

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)
})

Java

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)

Java

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, MediaSession को कमांड भेजने के लिए MediaController.TransportControls का इस्तेमाल करता है. आपको एक ऐसा कॉलबैक रजिस्टर करना होगा जो इन इवेंट का सही जवाब दे सके.

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)

Java

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 एट्रिब्यूट की सही वैल्यू देना ज़रूरी है. इसमें टाइटल और सबटाइटल की वैल्यू भी देनी होगी. इसमें आइकॉन यूआरआई या आइकॉन बिटमैप भी सेट होना चाहिए.

नीचे दिए गए कोड के उदाहरणों में, 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)

Java

@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);
}