Medya denetimleri

Android'deki medya denetimleri Hızlı Ayarlar'ın yakınındadır. Birden fazla uygulamadan gelen 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ın oturumlarında algılananlar gibi uzak yayınlar
  • Son çalındıkları sırayla önceki devam ettirilebilir oturumlar

Android 13'ten (API düzeyi 33) itibaren, kullanıcıların medya oynatan uygulamalara yönelik zengin medya denetimlerine erişebilmesi için medya denetimlerindeki işlem düğmeleri Player durumundan türetilir.

Bu sayede, cihazlarda tutarlı bir medya kontrolleri grubu ve daha kaliteli bir medya kontrolü deneyimi sunabilirsiniz.

Şekil 1'de, bunun bir telefon ve tablette sırasıyla nasıl görüneceği gösterilmektedir.

Düğmelerin nasıl görünebileceğini gösteren örnek bir kanal örneği kullanarak medyanın telefon ve tablet cihazlarında nasıl göründüğüyle ilgili kontroller
Şekil 1: Telefon ve tablet cihazlardaki medya kontrolleri

Sistem, aşağıdaki tabloda açıklandığı gibi Player durumuna göre en fazla beş işlem düğmesi gösterir. Kompakt modda, yalnızca ilk üç işlem alanı gösterilir. Bu ayarlar; Auto, Asistan ve Wear OS gibi diğer Android platformlarında medya denetimlerinin oluşturulma şekliyle uyumludur.

Yer Ölçütler İşlem
1 playWhenReady yanlış veya mevcut oynatma durumu STATE_ENDED. Çal
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 kullanılamaz. Ayrıca henüz yerleştirilmeyen özel düzenden özel bir komut, alanı doldurmak için kullanılabilir. Özel
(henüz Media3 ile desteklenmemektedir) PlaybackState ekstraları, EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV anahtarı için 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 kullanılamaz. Ayrıca henüz yerleştirilmeyen özel düzenden özel bir komut, alanı doldurmak için kullanılabilir. Özel
(henüz Media3 ile desteklenmemektedir) PlaybackState ekstraları, EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT anahtarı için true boole değeri içerir. Boş
4 Alanı doldurmak için henüz yerleştirilmeyen özel düzenden özel bir komut kullanılabilir. Özel
5 Alanı doldurmak için henüz yerleştirilmeyen ö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 kontrollerini Jetpack Media3 ile özelleştirmek için bir MediaSessionService uygularken oturumun özel düzenini ve denetleyicilerin kullanılabilir komutlarını buna göre ayarlayabilirsiniz:

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

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

  3. MediaSession.Callback.onCustomCommand() ürününde, 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);
    }
  }
}

Sistem gibi istemcilerin medya uygulamanıza bağlanabilmesi için MediaSession öğenizi yapılandırma hakkında daha fazla bilgi edinmek için Diğer istemcilere kontrol izni verme bölümüne bakın.

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

İşlem düğmelerine yanıt verme

Bir kullanıcı, sistem medya kontrollerindeki bir işlem düğmesine dokunduğunda sistemin MediaController cihazı MediaSession cihazınıza bir oynatma komutu gönderir. Ardından MediaSession, bu komutları oyuncuya delege eder. 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 konusunda yol gösterici bilgiler için Özel komutlar ekleme bölümüne bakın.

Android 13 Öncesi Davranış

Sistem kullanıcı arayüzü, geriye dönük uyumluluk amacıyla, 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, en çok beş işlemi eklendiği sırayla görüntüler. Kompakt modda, setShowActionsInCompactView() içine aktarılan değerlere göre belirlenen en fazla üç düğme gösterilir.

Özel işlemler, PlaybackState öğesine eklendikleri sıraya göre sıralanır.

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

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

Oynatmayı devam ettirme özelliği, Ayarlar uygulamasındaki Ses > Medya seçenekleri kullanılarak açılıp kapatılabilir. Kullanıcı, genişletilmiş bantta hızlıca kaydırdıktan sonra görünen dişli simgesine dokunarak da Ayarlar'a erişebilir.

Media3, medyaya devam ettirmeyi desteklemeyi kolaylaştıran API'ler sunar. Bu özelliğin uygulanmasıyla ilgili yol gösterici bilgiler için Media3 ile oynatmayı devam ettirme belgelerine bakın.

Eski medya API'lerini kullanma

Bu bölümde, eski MediaCompat API'leri kullanılarak sistem medya denetimleriyle nasıl entegrasyon sağlanacağı açıklanmaktadır.

Sistem aşağıdaki bilgileri MediaSession cihazının MediaMetadata cihazından 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 ayarlanmamışsa arama çubuğu ilerleme durumunu göstermez)

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

Medya oynatıcı, oynatılan medya için geçen süreyi MediaSession PlaybackState ile eşlenen arama çubuğuyla birlikte gösterir.

Medya oynatıcı, şu anda oynatılan medyanın ilerleme durumunu, MediaSession PlaybackState ile eşlenen arama çubuğuyla birlikte 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österir. Arama çubuğunun etkinleştirilmesi için PlaybackState.Builder#setActions öğesini uygulamanız ve ACTION_SEEK_TO eklemeniz gerekir.

Yer İşlem Ölçütler
1 Çal PlaybackState bilgisinin mevcut eyaleti aşağıdakilerden biridir:
  • STATE_NONE
  • STATE_STOPPED
  • STATE_PAUSED
  • STATE_ERROR
Yükleme döner simgesi PlaybackState bilgisinin mevcut eyaleti aşağıdakilerden biridir:
  • STATE_CONNECTING
  • STATE_BUFFERING
Duraklat PlaybackState bölgesinin mevcut eyaleti yukarıdakilerin hiçbirinden farklıdır.
2 Önceki PlaybackState işlem ACTION_SKIP_TO_PREVIOUS içeriyor.
Özel PlaybackState işlemleri ACTION_SKIP_TO_PREVIOUS içermiyor ve PlaybackState özel işlemi henüz uygulanmamış 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 ACTION_SKIP_TO_NEXT içeriyor.
Özel PlaybackState işlemleri ACTION_SKIP_TO_NEXT içermiyor ve PlaybackState özel işlemi henüz uygulanmamış 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şlemi henüz yerleştirilmemiş bir özel işlem içeriyor.
5 Özel PlaybackState özel işlemi henüz yerleştirilmemiş bir özel işlem içeriyor.

Standart işlemler ekle

Aşağıdaki kod örnekleri, PlaybackState standart ve özel işlemlerinin nasıl ekleneceğini göstermektedir.

Oynatma, duraklatma, önceki ve sonraki işlemleri için medya oturumundaki PlaybackState bölümünde bu işlemleri 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 istemiyorsanız ACTION_SKIP_TO_PREVIOUS veya ACTION_SKIP_TO_NEXT eklemeyin ve bunun yerine oturuma ekstra özellikler 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şlem ekleyin

Medya kontrollerinde gösterilmesini istediğiniz diğer işlemler için bir PlaybackStateCompat.CustomAction oluşturup bunu PlaybackState öğesine ekleyebilirsiniz. Bu işlemler eklendikleri sırada 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);

Oynatma Durumu işlemlerine yanıt verme

Kullanıcı bir düğmeye dokunduğunda SystemUI MediaController.TransportControls kullanarak MediaSession cihazına bir komut gönderir. Bu etkinliklere düzgün ş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ı Ayarlar alanında görünmesini sağlamak için geçerli bir MediaSession jetonuyla 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() öğesini kullanın.

Oynatmayı devam ettirmeyi desteklemek için uygulamaların bir MediaBrowserService ve MediaSession uygulaması gerekir. MediaSession uygulamanız, onPlay() geri çağırmasını uygulamalıdır.

MediaBrowserService uygulama

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

Sistem, SystemUI'den bir bağlantıyla MediaBrowserService cihazınızla iletişim kurmaya çalışır. Uygulamanız bu tür bağlantılara izin vermelidir, aksi takdirde oynatmayı devam ettirmeyi destekleyemez.

SystemUI'den gelen 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ı kontrolüyle ilgili 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 null olmayan bir kök döndürmelidir. Diğer karmaşık mantıklar onLoadChildren() içinde 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_SON sorgusu aldığında en son oynatılan medya öğesini döndürmelidir. Döndürülen değer, genel işlev yerine gerçek bir medya öğesi olmalıdır.

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

Aşağıdaki kod örnekleri, onGetRoot() uygulamasının nasıl uygulanacağını gösterir.

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