मीडिया ब्राउज़र सेवा बनाना

आपके ऐप्लिकेशन को, मेनिफ़ेस्ट फ़ाइल में इंटेंट-फ़िल्टर के साथ MediaBrowserService का एलान करना होगा. आपके पास अपनी सेवा का नाम चुनने का विकल्प होता है. यहां दिए गए उदाहरण में, चुनी गई सेवा का नाम MediaPlaybackService है.

<service android:name=".MediaPlaybackService">
  <intent-filter>
    <action android:name="android.media.browse.MediaBrowserService" />
  </intent-filter>
</service>

मीडिया सेशन शुरू करना

जब सेवा को onCreate() लाइफ़साइकल कॉलबैक मेथड मिलता है, तो उसे यह तरीका अपनाना चाहिए:

यहां दिए गए onCreate() कोड में इन चरणों को दिखाया गया है:

Kotlin

private const val MY_MEDIA_ROOT_ID = "media_root_id"
private const val MY_EMPTY_MEDIA_ROOT_ID = "empty_root_id"

class MediaPlaybackService : MediaBrowserServiceCompat() {

    private var mediaSession: MediaSessionCompat? = null
    private lateinit var stateBuilder: PlaybackStateCompat.Builder

    override fun onCreate() {
        super.onCreate()

        // Create a MediaSessionCompat
        mediaSession = MediaSessionCompat(baseContext, LOG_TAG).apply {

            // Enable callbacks from MediaButtons and TransportControls
            setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
                    or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
            )

            // Set an initial PlaybackState with ACTION_PLAY, so media buttons can start the player
            stateBuilder = PlaybackStateCompat.Builder()
                    .setActions(PlaybackStateCompat.ACTION_PLAY
                                    or PlaybackStateCompat.ACTION_PLAY_PAUSE
                    )
            setPlaybackState(stateBuilder.build())

            // MySessionCallback() has methods that handle callbacks from a media controller
            setCallback(MySessionCallback())

            // Set the session's token so that client activities can communicate with it.
            setSessionToken(sessionToken)
        }
    }
}

Java

public class MediaPlaybackService extends MediaBrowserServiceCompat {
    private static final String MY_MEDIA_ROOT_ID = "media_root_id";
    private static final String MY_EMPTY_MEDIA_ROOT_ID = "empty_root_id";

    private MediaSessionCompat mediaSession;
    private PlaybackStateCompat.Builder stateBuilder;

    @Override
    public void onCreate() {
        super.onCreate();

        // Create a MediaSessionCompat
        mediaSession = new MediaSessionCompat(context, LOG_TAG);

        // Enable callbacks from MediaButtons and TransportControls
        mediaSession.setFlags(
              MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
              MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);

        // Set an initial PlaybackState with ACTION_PLAY, so media buttons can start the player
        stateBuilder = new PlaybackStateCompat.Builder()
                            .setActions(
                                PlaybackStateCompat.ACTION_PLAY |
                                PlaybackStateCompat.ACTION_PLAY_PAUSE);
        mediaSession.setPlaybackState(stateBuilder.build());

        // MySessionCallback() has methods that handle callbacks from a media controller
        mediaSession.setCallback(new MySessionCallback());

        // Set the session's token so that client activities can communicate with it.
        setSessionToken(mediaSession.getSessionToken());
    }
}

क्लाइंट के साथ कनेक्शन मैनेज करना

MediaBrowserService में क्लाइंट कनेक्शन को मैनेज करने के दो तरीके होते हैं: onGetRoot() सेवा के ऐक्सेस को कंट्रोल करता है और onLoadChildren() क्लाइंट को MediaBrowserService के कॉन्टेंट के क्रम का मेन्यू बनाने और उसे दिखाने की सुविधा देता है.

onGetRoot() की मदद से क्लाइंट कनेक्शन कंट्रोल करना

onGetRoot() वाला तरीका, कॉन्टेंट के क्रम-अनुक्रम के रूट नोड को दिखाता है. अगर यह तरीका शून्य दिखाता है, तो कनेक्शन अस्वीकार कर दिया जाता है.

क्लाइंट को आपकी सेवा से कनेक्ट करने और उसके मीडिया कॉन्टेंट को ब्राउज़ करने की अनुमति देने के लिए, onGetRoot() को एक नॉन-नल BrowserRoot वापस करना होगा. यह एक रूट आईडी है, जो आपके कॉन्टेंट के क्रम को दिखाता है.

क्लाइंट को ब्राउज़ किए बिना MediaSession से कनेक्ट करने की अनुमति देने के लिए, onGetRoot() को अब भी एक नॉन-नल BrowserRoot दिखाना होगा. हालांकि, रूट आईडी में कॉन्टेंट की खाली हैरारकी दिखनी चाहिए.

onGetRoot() को लागू करने का सामान्य तरीका ऐसा दिख सकता है:

Kotlin

override fun onGetRoot(
        clientPackageName: String,
        clientUid: Int,
        rootHints: Bundle?
): MediaBrowserServiceCompat.BrowserRoot {

    // (Optional) Control the level of access for the specified package name.
    // You'll need to write your own logic to do this.
    return if (allowBrowsing(clientPackageName, clientUid)) {
        // Returns a root ID that clients can use with onLoadChildren() to retrieve
        // the content hierarchy.
        MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null)
    } else {
        // Clients can connect, but this BrowserRoot is an empty hierarchy
        // so onLoadChildren returns nothing. This disables the ability to browse for content.
        MediaBrowserServiceCompat.BrowserRoot(MY_EMPTY_MEDIA_ROOT_ID, null)
    }
}

Java

@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
    Bundle rootHints) {

    // (Optional) Control the level of access for the specified package name.
    // You'll need to write your own logic to do this.
    if (allowBrowsing(clientPackageName, clientUid)) {
        // Returns a root ID that clients can use with onLoadChildren() to retrieve
        // the content hierarchy.
        return new BrowserRoot(MY_MEDIA_ROOT_ID, null);
    } else {
        // Clients can connect, but this BrowserRoot is an empty hierarchy
        // so onLoadChildren returns nothing. This disables the ability to browse for content.
        return new BrowserRoot(MY_EMPTY_MEDIA_ROOT_ID, null);
    }
}

कुछ मामलों में, आपको यह कंट्रोल करना पड़ सकता है कि कौन आपके MediaBrowserService से कनेक्ट हो सकता है. इसके लिए, ऐक्सेस कंट्रोल लिस्ट (एसीएल) का इस्तेमाल किया जा सकता है. इससे यह तय किया जा सकता है कि किन कनेक्शन को अनुमति दी गई है. इसके अलावा, यह भी तय किया जा सकता है कि किन कनेक्शन को अनुमति नहीं दी जानी चाहिए. किसी खास कनेक्शन की अनुमति देने वाले एसीएल को लागू करने का उदाहरण देखने के लिए, Universal Android Music Player सैंपल ऐप्लिकेशन में PackageValidator क्लास देखें.

आपको इस बात का ध्यान रखना चाहिए कि क्वेरी किस तरह का क्लाइंट कर रहा है. इसके आधार पर, आपको कॉन्टेंट की अलग-अलग हैरारकी देनी चाहिए. खास तौर पर, Android Auto यह तय करता है कि उपयोगकर्ता ऑडियो ऐप्लिकेशन के साथ कैसे इंटरैक्ट करें. ज़्यादा जानकारी के लिए, ऑटो के लिए ऑडियो चलाना लेख पढ़ें. कनेक्शन के समय clientPackageName को देखकर, क्लाइंट टाइप का पता लगाया जा सकता है. साथ ही, क्लाइंट (या rootHints, अगर कोई है) के हिसाब से अलग BrowserRoot दिखाया जा सकता है.

onLoadChildren() के साथ कॉन्टेंट शेयर करना

क्लाइंट कनेक्ट होने के बाद, वह कॉन्टेंट के क्रम में आगे बढ़ सकता है. इसके लिए, उसे MediaBrowserCompat.subscribe() को बार-बार कॉल करना होगा, ताकि यूज़र इंटरफ़ेस (यूआई) का लोकल वर्शन बनाया जा सके. subscribe() तरीका, onLoadChildren() कॉलबैक को सेवा पर भेजता है. यह सेवा, MediaBrowser.MediaItem ऑब्जेक्ट की सूची दिखाती है.

हर MediaItem में एक यूनीक आईडी स्ट्रिंग होती है. यह एक ओपेक टोकन होता है. जब क्लाइंट को कोई सबमेन्यू खोलना होता है या कोई आइटम चलाना होता है, तो वह आईडी पास करता है. आईडी को सही मेन्यू नोड या कॉन्टेंट आइटम से जोड़ने की ज़िम्मेदारी आपकी सेवा की है.

onLoadChildren() को लागू करने का एक आसान तरीका ऐसा दिख सकता है:

Kotlin

override fun onLoadChildren(
        parentMediaId: String,
        result: MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>>
) {
    //  Browsing not allowed
    if (MY_EMPTY_MEDIA_ROOT_ID == parentMediaId) {
        result.sendResult(null)
        return
    }

    // Assume for example that the music catalog is already loaded/cached.

    val mediaItems = emptyList<MediaBrowserCompat.MediaItem>()

    // Check if this is the root menu:
    if (MY_MEDIA_ROOT_ID == parentMediaId) {
        // Build the MediaItem objects for the top level,
        // and put them in the mediaItems list...
    } else {
        // Examine the passed parentMediaId to see which submenu we're at,
        // and put the children of that menu in the mediaItems list...
    }
    result.sendResult(mediaItems)
}

Java

@Override
public void onLoadChildren(final String parentMediaId,
    final Result<List<MediaItem>> result) {

    //  Browsing not allowed
    if (TextUtils.equals(MY_EMPTY_MEDIA_ROOT_ID, parentMediaId)) {
        result.sendResult(null);
        return;
    }

    // Assume for example that the music catalog is already loaded/cached.

    List<MediaItem> mediaItems = new ArrayList<>();

    // Check if this is the root menu:
    if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {
        // Build the MediaItem objects for the top level,
        // and put them in the mediaItems list...
    } else {
        // Examine the passed parentMediaId to see which submenu we're at,
        // and put the children of that menu in the mediaItems list...
    }
    result.sendResult(mediaItems);
}

ध्यान दें: MediaBrowserService से डिलीवर किए गए MediaItem ऑब्जेक्ट में आइकॉन बिटमैप नहीं होने चाहिए. हर सामान के लिए MediaDescription बनाते समय, setIconUri() पर कॉल करके Uri का इस्तेमाल करें.

onLoadChildren() को लागू करने का उदाहरण देखने के लिए, Universal Android Music Player सैंपल ऐप्लिकेशन देखें.

मीडिया ब्राउज़र सेवा की लाइफ़साइकल

Android सेवा का व्यवहार इस बात पर निर्भर करता है कि उसे एक या उससे ज़्यादा क्लाइंट से शुरू किया गया है या बाउंड किया गया है. सेवा बनाने के बाद, इसे शुरू किया जा सकता है, बाइंड किया जा सकता है या दोनों काम किए जा सकते हैं. इन सभी राज्यों में, यह सेवा पूरी तरह से काम करती है और वह काम कर सकती है जिसके लिए इसे डिज़ाइन किया गया है. हालांकि, यह सेवा कितने समय तक उपलब्ध रहेगी, यह अलग-अलग राज्यों में अलग-अलग हो सकता है. जब तक सभी क्लाइंट, बाइंड की गई सेवा को अनबाइंड नहीं कर देते, तब तक उसे बंद नहीं किया जाता. शुरू की गई किसी सेवा को साफ़ तौर पर रोका और बंद किया जा सकता है. हालांकि, ऐसा तब किया जा सकता है, जब वह किसी भी क्लाइंट से न जुड़ी हो.

जब किसी दूसरी ऐक्टिविटी में चल रहा MediaBrowser, किसी MediaBrowserService से कनेक्ट होता है, तो यह ऐक्टिविटी को सेवा से बाइंड करता है. इससे सेवा बाइंड हो जाती है, लेकिन शुरू नहीं होती. यह डिफ़ॉल्ट व्यवहार, MediaBrowserServiceCompat क्लास में पहले से मौजूद होता है.

सिर्फ़ बाइंड की गई (और शुरू नहीं की गई) सेवा तब बंद हो जाती है, जब उसके सभी क्लाइंट अनबाइंड हो जाते हैं. अगर इस समय आपका यूज़र इंटरफ़ेस (यूआई) डिसकनेक्ट हो जाता है, तो सेवा बंद हो जाती है. अगर आपने अब तक कोई संगीत नहीं चलाया है, तो यह समस्या नहीं है. हालांकि, जब वीडियो चलने लगता है, तो उपयोगकर्ता शायद यह उम्मीद करता है कि ऐप्लिकेशन बदलने के बाद भी वह वीडियो सुनता रहे. आपको यूज़र इंटरफ़ेस (यूआई) को किसी दूसरे ऐप्लिकेशन के साथ काम करने के लिए अनबाइंड करते समय, प्लेयर को बंद नहीं करना है.

इसलिए, आपको यह पक्का करना होगा कि startService() को कॉल करके संगीत चलाने की सुविधा शुरू की गई हो. शुरू की गई सेवा को साफ़ तौर पर बंद करना ज़रूरी है. भले ही, वह सेवा बाइंड की गई हो या नहीं. इससे यह पक्का होता है कि कंट्रोल करने वाले यूज़र इंटरफ़ेस (यूआई) की गतिविधि अनबाइंड होने पर भी, आपका प्लेयर काम करता रहे.

चालू की गई किसी सेवा को बंद करने के लिए, Context.stopService() या stopSelf() पर कॉल करें. सिस्टम, सेवा को जल्द से जल्द बंद कर देता है और उसे मिटा देता है. हालांकि, अगर एक या उससे ज़्यादा क्लाइंट अब भी सेवा से जुड़े हैं, तो सेवा को रोकने के लिए किए गए कॉल में तब तक देरी होती है, जब तक सभी क्लाइंट सेवा से अलग नहीं हो जाते.

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

  • यह सेवा तब बनाई जाती है, जब इसे मीडिया बटन के जवाब में शुरू किया जाता है या जब कोई गतिविधि इससे जुड़ती है. ऐसा तब होता है, जब गतिविधि MediaBrowser के ज़रिए कनेक्ट हो जाती है.
  • मीडिया सेशन के onPlay() कॉलबैक में ऐसा कोड शामिल होना चाहिए जो startService() को कॉल करता हो. इससे यह पक्का होता है कि सेवा शुरू हो और चलती रहे. भले ही, इससे जुड़ी सभी यूज़र इंटरफ़ेस (यूआई) MediaBrowser गतिविधियां अनबाइंड हो जाएं.
  • onStop() कॉलबैक को stopSelf() को कॉल करना चाहिए. अगर सेवा शुरू की गई थी, तो यह उसे बंद कर देता है. इसके अलावा, अगर इससे जुड़ी कोई गतिविधि नहीं है, तो सेवा बंद कर दी जाती है. ऐसा न होने पर, सेवा तब तक बंधी रहती है, जब तक उसकी सभी गतिविधियां अनबाइंड नहीं हो जातीं. (अगर सेवा बंद होने से पहले, बाद में startService() कॉल आता है, तो सेवा बंद करने का अनुरोध रद्द कर दिया जाता है.)

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

सेवा का लाइफ़साइकल

फ़ोरग्राउंड सेवा के साथ MediaStyle सूचनाओं का इस्तेमाल करना

जब कोई सेवा चल रही हो, तो उसे फ़ोरग्राउंड में चलना चाहिए. इससे सिस्टम को यह पता चलता है कि सेवा कोई ज़रूरी काम कर रही है. इसलिए, अगर सिस्टम में मेमोरी कम हो, तो इसे बंद नहीं किया जाना चाहिए. फ़ोरग्राउंड सेवा को एक सूचना दिखानी चाहिए, ताकि उपयोगकर्ता को इसके बारे में पता चल सके. साथ ही, वह चाहें, तो इसे कंट्रोल कर सके. onPlay() कॉलबैक को सेवा को फ़ोरग्राउंड में रखना चाहिए. (ध्यान दें कि "फ़ोरग्राउंड" का यह खास मतलब है. Android, प्रोसेस मैनेजमेंट के लिए इस सेवा को फ़ोरग्राउंड में मानता है. हालांकि, उपयोगकर्ता के लिए प्लेयर बैकग्राउंड में चलता है, जबकि स्क्रीन पर कोई दूसरा ऐप्लिकेशन "फ़ोरग्राउंड" में दिखता है.)

जब कोई सेवा फ़ोरग्राउंड में चलती है, तो उसे सूचना दिखानी चाहिए. सबसे सही तरीका यह है कि सूचना में एक या उससे ज़्यादा ट्रांसपोर्ट कंट्रोल शामिल हों. सूचना में, सेशन के मेटाडेटा से मिली काम की जानकारी भी शामिल होनी चाहिए.

जब प्लेयर चलना शुरू करे, तब सूचना बनाएं और दिखाएं. ऐसा करने के लिए, MediaSessionCompat.Callback.onPlay() तरीके का इस्तेमाल करना सबसे अच्छा है.

यहां दिए गए उदाहरण में NotificationCompat.MediaStyle का इस्तेमाल किया गया है. इसे मीडिया ऐप्लिकेशन के लिए डिज़ाइन किया गया है. इसमें ऐसी सूचना बनाने का तरीका बताया गया है जिसमें मेटाडेटा और ट्रांसपोर्ट कंट्रोल दिखते हैं. सुविधाजनक तरीका getController() आपको सीधे मीडिया सेशन से मीडिया कंट्रोलर बनाने की अनुमति देता है.

Kotlin

// Given a media session and its context (usually the component containing the session)
// Create a NotificationCompat.Builder

// Get the session's metadata
val controller = mediaSession.controller
val mediaMetadata = controller.metadata
val description = mediaMetadata.description

val builder = NotificationCompat.Builder(context, channelId).apply {
    // Add the metadata for the currently playing track
    setContentTitle(description.title)
    setContentText(description.subtitle)
    setSubText(description.description)
    setLargeIcon(description.iconBitmap)

    // Enable launching the player by clicking the notification
    setContentIntent(controller.sessionActivity)

    // Stop the service when the notification is swiped away
    setDeleteIntent(
            MediaButtonReceiver.buildMediaButtonPendingIntent(
                    context,
                    PlaybackStateCompat.ACTION_STOP
            )
    )

    // Make the transport controls visible on the lockscreen
    setVisibility(NotificationCompat.VISIBILITY_PUBLIC)

    // Add an app icon and set its accent color
    // Be careful about the color
    setSmallIcon(R.drawable.notification_icon)
    color = ContextCompat.getColor(context, R.color.primaryDark)

    // Add a pause button
    addAction(
            NotificationCompat.Action(
                    R.drawable.pause,
                    getString(R.string.pause),
                    MediaButtonReceiver.buildMediaButtonPendingIntent(
                            context,
                            PlaybackStateCompat.ACTION_PLAY_PAUSE
                    )
            )
    )

    // Take advantage of MediaStyle features
    setStyle(android.support.v4.media.app.NotificationCompat.MediaStyle()
            .setMediaSession(mediaSession.sessionToken)
            .setShowActionsInCompactView(0)

            // Add a cancel button
            .setShowCancelButton(true)
            .setCancelButtonIntent(
                    MediaButtonReceiver.buildMediaButtonPendingIntent(
                            context,
                            PlaybackStateCompat.ACTION_STOP
                    )
            )
    )
}

// Display the notification and place the service in the foreground
startForeground(id, builder.build())

Java

// Given a media session and its context (usually the component containing the session)
// Create a NotificationCompat.Builder

// Get the session's metadata
MediaControllerCompat controller = mediaSession.getController();
MediaMetadataCompat mediaMetadata = controller.getMetadata();
MediaDescriptionCompat description = mediaMetadata.getDescription();

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId);

builder
    // Add the metadata for the currently playing track
    .setContentTitle(description.getTitle())
    .setContentText(description.getSubtitle())
    .setSubText(description.getDescription())
    .setLargeIcon(description.getIconBitmap())

    // Enable launching the player by clicking the notification
    .setContentIntent(controller.getSessionActivity())

    // Stop the service when the notification is swiped away
    .setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context,
       PlaybackStateCompat.ACTION_STOP))

    // Make the transport controls visible on the lockscreen
    .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)

    // Add an app icon and set its accent color
    // Be careful about the color
    .setSmallIcon(R.drawable.notification_icon)
    .setColor(ContextCompat.getColor(context, R.color.primaryDark))

    // Add a pause button
    .addAction(new NotificationCompat.Action(
        R.drawable.pause, getString(R.string.pause),
        MediaButtonReceiver.buildMediaButtonPendingIntent(context,
            PlaybackStateCompat.ACTION_PLAY_PAUSE)))

    // Take advantage of MediaStyle features
    .setStyle(new MediaStyle()
        .setMediaSession(mediaSession.getSessionToken())
        .setShowActionsInCompactView(0)

        // Add a cancel button
       .setShowCancelButton(true)
       .setCancelButtonIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context,
           PlaybackStateCompat.ACTION_STOP)));

// Display the notification and place the service in the foreground
startForeground(id, builder.build());

MediaStyle सूचनाओं का इस्तेमाल करते समय, इन NotificationCompat सेटिंग के बारे में जान लें:

  • setContentIntent() का इस्तेमाल करने पर, सूचना पर क्लिक करने के बाद आपकी सेवा अपने-आप शुरू हो जाती है. यह एक काम की सुविधा है.
  • लॉक स्क्रीन जैसी "भरोसेमंद नहीं" स्थिति में, सूचना के कॉन्टेंट के लिए डिफ़ॉल्ट रूप से VISIBILITY_PRIVATE विकल्प चुना जाता है. आपको शायद लॉकस्क्रीन पर ट्रांसपोर्ट कंट्रोल देखने हों. इसलिए, VISIBILITY_PUBLIC को चुनें.
  • बैकग्राउंड का रंग सेट करते समय सावधानी बरतें. Android 5.0 या उसके बाद के वर्शन में, सामान्य सूचना के लिए रंग सिर्फ़ ऐप्लिकेशन के छोटे आइकॉन के बैकग्राउंड पर लागू होता है. हालांकि, Android 7.0 से पहले के MediaStyle नोटिफ़िकेशन के लिए, इस रंग का इस्तेमाल पूरे नोटिफ़िकेशन के बैकग्राउंड के लिए किया जाता है. बैकग्राउंड के रंग की जांच करें. ऐसे रंग चुनें जो आंखों को सुकून दें. बहुत ज़्यादा चमकदार या फ़्लोरोसेंट रंगों का इस्तेमाल न करें.

ये सेटिंग सिर्फ़ तब उपलब्ध होती हैं, जब NotificationCompat.MediaStyle का इस्तेमाल किया जा रहा हो:

  • सूचना को अपने सेशन से जोड़ने के लिए, setMediaSession() का इस्तेमाल करें. इससे तीसरे पक्ष के ऐप्लिकेशन और साथ में इस्तेमाल किए जाने वाले डिवाइसों को सेशन को ऐक्सेस और कंट्रोल करने की अनुमति मिलती है.
  • नोटिफ़िकेशन के स्टैंडर्ड साइज़ वाले contentView में ज़्यादा से ज़्यादा तीन कार्रवाइयां दिखाने के लिए, setShowActionsInCompactView() का इस्तेमाल करें. (यहां 'रोकें' बटन के बारे में बताया गया है.)
  • Android 5.0 (एपीआई लेवल 21) और इसके बाद के वर्शन में, फ़ोरग्राउंड में सेवा बंद होने के बाद, प्लेयर को रोकने के लिए सूचना को स्वाइप करके खारिज किया जा सकता है. हालांकि, ऐसा पिछले वर्शन में नहीं किया जा सकता. Android 5.0 (एपीआई लेवल 21) से पहले के वर्शन पर, उपयोगकर्ताओं को सूचना हटाने और मीडिया चलाने की सुविधा बंद करने की अनुमति देने के लिए, सूचना के सबसे ऊपर दाएं कोने में रद्द करें बटन जोड़ा जा सकता है. इसके लिए, setShowCancelButton(true) और setCancelButtonIntent() को कॉल करें.

रोकें और रद्द करें बटन जोड़ने पर, आपको PendingIntent को प्लेबैक ऐक्शन से अटैच करना होगा. MediaButtonReceiver.buildMediaButtonPendingIntent() तरीका, PlaybackState कार्रवाई को PendingIntent में बदलने का काम करता है.

AVRCP मीडिया ब्राउज़िंग की सुविधा चालू करना

Android Auto जैसे कस्टम ऐप्लिकेशन के अलावा, सिस्टम की ब्लूटूथ लेयर भी आपके MediaBrowserService के क्लाइंट के तौर पर काम करती है. इससे वायरलेस रिमोट कैटलॉग ब्राउज़िंग (एवीआरसीपी) की सुविधा मिलती है.

Android 16 और Android 17 पर, प्लैटफ़ॉर्म को यह ज़रूरी है कि Media3 का इस्तेमाल न करने वाले ऐप्लिकेशन, ब्राउज़ करने के लिए मान्य होने के लिए, इंटेंट फ़िल्टर के साथ कोई खास गतिविधि दिखाएं.

इस खास इंटेंट फ़िल्टर को अपने AndroidManifest.xml में एक्सपोर्ट की गई किसी गतिविधि में जोड़ें. ध्यान दें कि CATEGORY_DEFAULT को जान-बूझकर शामिल नहीं किया गया है, ताकि आपका ऐप्लिकेशन स्थानीय ऑडियो फ़ाइलों के लिए, सामान्य "इससे खोलें" मेन्यू में न दिखे:

<activity
    android:name=".BluetoothValidationActivity"
    android:exported="true"
    android:theme="@android:style/Theme.NoDisplay"
    android:excludeFromRecents="true"
    android:noHistory="true">
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="content" />
    <data android:host="media" />
    <!-- Specific path check used by Bluetooth stack for validation -->
    <data android:pathPrefix="/internal/audio/media/" />
    <data android:mimeType="audio/*" />
  </intent-filter>
</activity>