Medya denetimleri

Android'deki medya denetimleri Hızlı Ayarlar'ın yanında yer alır. Birden fazla uygulamadan gerçekleştirilen oturumlar, kaydırılabilir bir bantta düzenlenir. Bant, oturumları şu sırayla listeler:

  • Telefonda yerel olarak oynatılan canlı yayınlar
  • Harici cihazlarda veya yayınlama oturumlarında algılananlar gibi uzak akışlar
  • Son oynandıkları sıraya göre önceki devam ettirilebilir oturumlar

Android 13'ten (API düzeyi 33) başlayarak, kullanıcıların medya oynatan uygulamalarla ilgili zengin medya denetimlerine erişebilmesi için medya denetimlerindeki işlem düğmeleri Player durumundan türetilmiştir.

Böylece, tüm cihazlarda tutarlı bir medya denetimi grubu ve daha gelişmiş bir medya kontrol deneyimi sunabilirsiniz.

Şekil 1'de bu özelliğin bir telefonda ve tablet cihazda nasıl görüneceğine dair bir örnek gösterilmiştir.

Düğmelerin nasıl görüneceğini gösteren örnek bir kanal örneğine yer verilen örnek bir kanalla, telefon ve tablet cihazlarda nasıl göründükleri açısından medya kontrolleri
Şekil 1: Telefon ve tablet cihazlardaki medya kontrolleri

Sistem, aşağıdaki tabloda açıklandığı gibi Player durumuna dayalı olarak en fazla beş işlem düğmesi görüntüler. Kompakt modda yalnızca ilk üç işlem slotu gösterilir. Bu aynı zamanda medya denetimlerinin Auto, Asistan ve Wear OS gibi diğer Android platformlarında oluşturulma şekliyle de uyumludur.

Yer Ölçütler İşlem
1 playWhenReady yanlış veya geçerli oynatma durumu STATE_ENDED şeklindedir. Oynat
playWhenReady doğru ve mevcut oynatma durumu STATE_BUFFERING. Yükleme döner simgesi
playWhenReady doğru ve mevcut oynatma durumu STATE_READY. Duraklat
2 Oynatıcı komutu COMMAND_SEEK_TO_PREVIOUS veya COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM kullanılabilir. Önceki
COMMAND_SEEK_TO_PREVIOUS veya COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM oynatıcı komutu mevcut değildir. Ayrıca, alanı doldurmak için henüz yerleştirilmemiş özel düzenden özel bir komut kullanılabilir. Özel
(henüz Media3 ile desteklenmemektedir) PlaybackState ekstraları EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV anahtarı için bir true boole değeri içerir. Boş
3 Oynatıcı komutu COMMAND_SEEK_TO_NEXT veya COMMAND_SEEK_TO_NEXT_MEDIA_ITEM kullanılabilir. Sonraki
COMMAND_SEEK_TO_NEXT veya COMMAND_SEEK_TO_NEXT_MEDIA_ITEM oynatıcı komutu mevcut değildir. Ayrıca, alanı doldurmak için henüz yerleştirilmemiş özel düzenden özel bir komut kullanılabilir. Özel
(henüz Media3 ile desteklenmemektedir) PlaybackState ekstraları EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT anahtarı için bir true boole değeri içerir. Boş
4 Alanı doldurmak için, henüz yerleştirilmemiş özel düzenden özel bir komut kullanılabilir. Özel
5 Alanı doldurmak için, henüz yerleştirilmemiş özel düzenden özel bir komut kullanılabilir. Özel

Özel komutlar, özel düzene eklendikleri sırayla yerleştirilir.

Komut düğmelerini özelleştir

Sistem medya denetimlerini Jetpack Media3 ile özelleştirmek için MediaSessionService uygularken oturumun özel düzenini ve denetleyicilerin kullanılabilir komutlarını buna göre ayarlayabilirsiniz:

  1. onCreate() ürününde MediaSession oluşturun ve komut düğmelerinin özel düzenini tanımlayın.

  2. MediaSession.Callback.onConnect()'da özel komutlar dahil olmak üzere mevcut komutlarını ConnectionResult içinde tanımlayarak denetleyicileri yetkilendirin.

  3. MediaSession.Callback.onCustomCommand()'da, kullanıcı tarafından seçilen özel komuta yanıt verin.

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 öğenizi sistem gibi istemcilerin medya uygulamanıza bağlanabileceği şekilde yapılandırma hakkında daha fazla bilgi edinmek için Diğer istemcilere kontrol verme bölümüne bakın.

Jetpack Media3 ile bir MediaSession uyguladığınızda PlaybackState cihazınız medya oynatıcı ile otomatik olarak güncel tutulur. Benzer şekilde, bir MediaSessionService uyguladığınızda kitaplık sizin için otomatik olarak MediaStyle bildirim yayınlar ve güncel tutar.

İşlem düğmelerine yanıt verme

Kullanıcı, sistem medya denetimlerindeki bir işlem düğmesine dokunduğunda, sistemin MediaController'i MediaSession cihazınıza bir oynatma komutu gönderir. Ardından MediaSession, bu komutları oyuncuya devreder. Media3'ün Player arayüzünde tanımlanan komutlar, medya oturumu tarafından otomatik olarak işlenir.

Özel bir komuta nasıl yanıt verileceği hakkında yardım için Özel komutlar ekleme bölümüne bakın.

Android 13 Öncesinde Davranış

Geriye dönük uyumluluk amacıyla Sistem Kullanıcı Arayüzü, Android 13'ü hedefleyecek şekilde güncellenmeyen veya PlaybackState bilgilerini içermeyen uygulamalar için bildirim işlemleri kullanan alternatif bir düzen sağlamaya devam etmektedir. İşlem düğmeleri, MediaStyle bildirimine ekli Notification.Action listesinden türetilir. Sistem, eklendikleri sırayla en çok beş işlem görüntüler. Kompakt modda, setShowActionsInCompactView() öğesine geçirilen değerlere göre belirlenen en fazla üç düğme gösterilir.

Özel işlemler, PlaybackState öğesine eklendikleri sırayla yerleştirilir.

Aşağıdaki kod örneğinde, MediaStyle bildirimine nasıl işlem ekleneceği gösterilmektedir :

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();

Medyayı devam ettirmeyi destekle

Medya devam ettirme, kullanıcıların uygulamayı başlatmak zorunda kalmadan önceki oturumları banttan yeniden başlatmalarına olanak tanır. Oynatma başladığında kullanıcı, medya kontrolleriyle her zamanki gibi etkileşimde bulunur.

Oynatma devam ettirme özelliği, Ayarlar uygulaması kullanılarak Ses > Medya seçenekleri altından açılabilir ve kapatılabilir. Kullanıcı, Ayarlar'a, genişletilmiş atlı karıncada kaydırdıktan sonra görünen dişli simgesine dokunarak da erişebilir.

Media3, medya devam ettirmeyi kolaylaştırmak için API'ler sunar. Bu özelliğin uygulanması hakkında yardım almak için Media3 ile oynatma devam ettirme dokümanlarına bakın.

Eski medya API'larını kullanma

Bu bölümde, eski MediaCompat API'lerini kullanarak sistem medya denetimleriyle nasıl entegrasyon yapılacağı açıklanmaktadır.

Sistem, MediaSession MediaMetadata öğesinden aşağıdaki bilgileri alır ve kullanılabilir olduğunda görüntüler:

  • METADATA_KEY_ALBUM_ART_URI
  • METADATA_KEY_TITLE
  • METADATA_KEY_DISPLAY_TITLE
  • METADATA_KEY_ARTIST
  • METADATA_KEY_DURATION (Süre ayarlanmazsa arama çubuğunda ilerleme durumu gösterilmez)

Geçerli ve doğru bir medya denetimi bildiriminiz olduğundan emin olmak için METADATA_KEY_TITLE veya METADATA_KEY_DISPLAY_TITLE meta verilerinin değerini, oynatılmakta olan medyanın başlığına ayarlayın.

Medya oynatıcı, şu anda oynatılan medya için geçen süreyi ve MediaSession PlaybackState ile eşleştirilmiş arama çubuğunu gösterir.

Medya oynatıcı, şu anda oynatılan medyanın ilerleme durumunu ve MediaSession PlaybackState ile eşleştirilmiş bir arama çubuğu gösterir. Arama çubuğu, kullanıcıların konumu değiştirmesine olanak tanır ve medya öğesi için geçen süreyi görüntüler. Arama çubuğunun etkinleştirilmesi için PlaybackState.Builder#setActions işlemini uygulamanız ve ACTION_SEEK_TO eklemeniz gerekir.

Yer İşlem Ölçütler
1 Oynat PlaybackState için mevcut durum aşağıdakilerden biridir:
  • STATE_NONE
  • STATE_STOPPED
  • STATE_PAUSED
  • STATE_ERROR
Yükleme döner simgesi PlaybackState için mevcut eyalet aşağıdakilerden biridir:
  • STATE_CONNECTING
  • STATE_BUFFERING
Duraklat PlaybackState öğesinin mevcut durumu yukarıdakilerin hiçbiri değil.
2 Önceki PlaybackState işlem şunları içeriyor: ACTION_SKIP_TO_PREVIOUS.
Özel PlaybackState işlem ACTION_SKIP_TO_PREVIOUS içermiyor. PlaybackState özel işlemi ise henüz yerleştirilmemiş bir özel işlem içeriyor.
Boş PlaybackState ekstralar, SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV anahtarı için true boole değeri içerir.
3 Sonraki PlaybackState işlem şunları içeriyor: ACTION_SKIP_TO_NEXT.
Özel PlaybackState işlem ACTION_SKIP_TO_NEXT içermiyor. PlaybackState özel işlemi ise henüz yerleştirilmemiş bir özel işlem içeriyor.
Boş PlaybackState ekstralar, SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT anahtarı için true boole değeri içerir.
4 Özel PlaybackState özel işlem henüz yerleştirilmemiş bir özel işlem içeriyor.
5 Özel PlaybackState özel işlem henüz yerleştirilmemiş bir özel işlem içeriyor.

Standart işlemler ekleyin

Aşağıdaki kod örneklerinde PlaybackState standart ve özel işlemlerinin nasıl ekleneceği gösterilmektedir.

Oynatma, duraklatma, önceki ve sonraki için bu işlemleri medya oturumunun PlaybackState bölümünde ayarlayın.

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

Önceki veya sonraki alanlarda düğme olmasını istemiyorsanız ACTION_SKIP_TO_PREVIOUS veya ACTION_SKIP_TO_NEXT öğelerini eklemeyin, bunun yerine oturuma ekstra öğeler ekleyin:

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

Özel işlemler ekleme

Medya denetimlerinde gösterilmesini istediğiniz diğer işlemler için PlaybackStateCompat.CustomAction oluşturup bunu PlaybackState öğesine ekleyebilirsiniz. Bu işlemler eklendikleri sırayla gösterilir.

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 işlemlerine yanıt verme

Kullanıcı bir düğmeye dokunduğunda SystemUI, MediaSession cihazına geri bir komut göndermek için MediaController.TransportControls aracını kullanır. Bu etkinliklere doğru şekilde yanıt verebilecek bir geri çağırma kaydetmeniz gerekir.

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

Medyayı Devam Ettirme

Oynatıcı uygulamanızın hızlı ayar ayarları alanında görünmesini sağlamak için geçerli MediaSession jetonu içeren bir MediaStyle bildirimi oluşturmanız gerekir.

MediaStyle bildiriminin başlığını görüntülemek için NotificationBuilder.setContentTitle() öğesini kullanın.

Medya oynatıcıda marka simgesini görüntülemek için NotificationBuilder.setSmallIcon() değerini kullanın.

Oynatmayı devam ettirmeyi desteklemek için uygulamaların bir MediaBrowserService ve MediaSession uygulaması gerekir. MediaSession öğeniz, onPlay() geri çağırma işlevini uygulamalıdır.

MediaBrowserService uygulama

Cihaz başlatıldıktan sonra, sistem en son kullanılan beş medya uygulamasını arar ve her uygulamadan oynatmayı yeniden başlatmak için kullanılabilecek denetimler sağlar.

Sistem, SystemUI'den bir bağlantı üzerinden MediaBrowserService cihazınızla iletişim kurmaya çalışır. Uygulamanızın bu tür bağlantılara izin vermesi gerekir, aksi halde oynatma devam ettirmeyi destekleyemez.

SystemUI ile kurulan bağlantılar, paket adı com.android.systemui ve imza kullanılarak tanımlanıp doğrulanabilir. SystemUI, platform imzasıyla imzalanır. Platform imzasının nasıl kontrol edileceğini gösteren bir örneği UAMP uygulamasında bulabilirsiniz.

Oynatmayı devam ettirmeyi desteklemek için MediaBrowserService cihazınızın şu davranışları uygulaması gerekir:

  • onGetRoot(), hızlı bir şekilde boş olmayan bir kök döndürmelidir. Diğer karmaşık mantıklar onLoadChildren() konumunda ele alınmalıdır

  • Kök medya kimliğinde onLoadChildren() çağrıldığında, sonuç bir FLAG_PLAYABLE alt öğesi içermelidir.

  • MediaBrowserService, EXTRA_RECENT sorgusu aldığında en son oynatılan medya öğesini döndürecektir. Döndürülen değer, genel bir işlev değil, gerçek bir medya öğesi olmalıdır.

  • MediaBrowserService, boş olmayan bir başlık ve altyazı ile uygun bir MediaDescription sağlamalıdır. Ayrıca, bir simge URI'si veya bir simge bit eşlemi de ayarlamalıdır.

Aşağıdaki kod örneklerinde onGetRoot() özelliğinin nasıl uygulanacağı gösterilmektedir.

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