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.
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 .
|
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 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:
onCreate()
'de birMediaSession
oluşturun ve komut düğmelerinin özel düzenini tanımlayın.MediaSession.Callback.onConnect()
'da, özel komutlar dahil olmak üzere kullanılabilir komutlarınıConnectionResult
içinde tanımlayarak denetleyicileri yetkilendirin.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 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); } } }
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 | Oynat |
PlaybackState bilgisinin mevcut eyaleti aşağıdakilerden biridir:
|
Yükleme döner simgesi |
PlaybackState bilgisinin mevcut eyaleti aşağıdakilerden biridir:
|
|
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ıklaronLoadChildren()
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); }