Mediensteuerung

Die Mediensteuerung in Android befindet sich in der Nähe der Schnelleinstellungen. Sitzungen ab Mehrere Apps sind in einem wischbaren Karussell angeordnet. Das Karussell enthält Sitzungen in dieser Reihenfolge:

  • Streams, die lokal auf dem Smartphone wiedergegeben werden
  • Remote-Streams, z. B. von externen Geräten oder Streamingsitzungen erkannte Streams
  • Vorherige fortsetzbare Sitzungen in der Reihenfolge, in der sie zuletzt gespielt wurden

Ab Android 13 (API-Level 33), damit Nutzer auf umfassende Mediensteuerung für Apps, die Medien wiedergeben, Aktionsschaltflächen bei der Mediensteuerung werden aus dem Status Player abgeleitet.

So können Sie einheitliche Mediensteuerelemente und ein ausgefeilteres Mediensteuerung geräteübergreifend.

Abbildung 1 zeigt ein Beispiel dafür, wie dies auf einem Smartphone und Tablet aussieht. .

<ph type="x-smartling-placeholder">
</ph> Steuerelemente für Medien: Sie können festlegen, wie sie auf Smartphones und Tablets erscheinen,
            anhand eines Beispiel-Tracks, der zeigt, wie die Schaltflächen aussehen können
Abbildung 1 : Mediensteuerung auf Smartphones und Tablets

Das System zeigt je nach Status Player bis zu fünf Aktionsschaltflächen an: wie in der folgenden Tabelle beschrieben. Im kompakten Modus sind nur die ersten drei Aktionen werden angezeigt. Das entspricht der Darstellung der Mediensteuerelemente in anderen Android-Plattformen wie Auto, Assistant und Wear OS

Stellen Kriterien Aktion
1 playWhenReady „false“ ist oder die aktuelle Wiedergabe Bundesland ist STATE_ENDED. Wiedergeben
playWhenReady ist „true“ und der aktuelle Wiedergabestatus ist STATE_BUFFERING. Rotierendes Ladesymbol
playWhenReady ist „true“ und der aktuelle Wiedergabestatus ist STATE_READY. Pausieren
2 Player-Befehl COMMAND_SEEK_TO_PREVIOUS oder COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM ist verfügbar. Zurück
Weder der Player-Befehl COMMAND_SEEK_TO_PREVIOUS noch COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM ist verfügbar. Außerdem ist ein benutzerdefinierter Befehl aus dem benutzerdefinierten Layout, der noch nicht platziert wurde, zum Füllen der Anzeigenfläche verfügbar. Benutzerdefiniert
(noch nicht unterstützt bei Media3) PlaybackState-Extras beinhalten einen booleschen Wert true für den Schlüssel EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV. Leer
3 Player-Befehl COMMAND_SEEK_TO_NEXT oder COMMAND_SEEK_TO_NEXT_MEDIA_ITEM ist verfügbar. Weiter
Weder der Player-Befehl COMMAND_SEEK_TO_NEXT noch COMMAND_SEEK_TO_NEXT_MEDIA_ITEM ist verfügbar. Außerdem ist ein benutzerdefinierter Befehl aus dem benutzerdefinierten Layout, der noch nicht platziert wurde, zum Füllen der Anzeigenfläche verfügbar. Benutzerdefiniert
(noch nicht unterstützt bei Media3) PlaybackState-Extras beinhalten einen booleschen Wert true für den Schlüssel EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT. Leer
4 Ein benutzerdefinierter Befehl aus dem benutzerdefinierten Layout, der noch nicht platziert wurde, ist zum Füllen der Anzeigenfläche verfügbar. Benutzerdefiniert
5 Ein benutzerdefinierter Befehl aus dem benutzerdefinierten Layout, der noch nicht platziert wurde, ist zum Füllen der Anzeigenfläche verfügbar. Benutzerdefiniert

Benutzerdefinierte Befehle werden in der Reihenfolge platziert, in der sie zum benutzerdefiniertes Layout.

Befehlsschaltflächen anpassen

So passen Sie die Mediensteuerung des Systems mit Jetpack Media3 an: können Sie das benutzerdefinierte Layout der Sitzung und die verfügbaren Befehle für die Verantwortlichen bei der Implementierung einer MediaSessionService:

  1. In onCreate() eine MediaSession erstellen und das benutzerdefinierte Layout definieren von Befehlsschaltflächen.

  2. In MediaSession.Callback.onConnect(): Controller autorisieren, indem sie ihre verfügbaren Befehle definieren, einschließlich benutzerdefinierte Befehle, in ConnectionResult.

  3. In MediaSession.Callback.onCustomCommand(): auf den vom Nutzer ausgewählten benutzerdefinierten Befehl antworten.

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

Weitere Informationen zur Konfiguration von MediaSession, damit Clients wie die System eine Verbindung zu Ihrer Medien-App herstellen kann, finden Sie Anderen Clients die Kontrolle gewähren

Wenn Sie mit Jetpack Media3 eine MediaSession implementieren, wird Ihre PlaybackState wird automatisch über den Mediaplayer auf dem neuesten Stand gehalten. Ähnlich verhält es sich, wenn Sie implementieren MediaSessionService, veröffentlicht die Bibliothek automatisch eine MediaStyle Benachrichtigung und hält sie auf dem neuesten Stand.

Auf Aktionsschaltflächen reagieren

Wenn ein Nutzer in der Mediensteuerung des Systems auf eine Aktionsschaltfläche tippt, MediaController sendet einen Wiedergabebefehl an MediaSession. Die MediaSession delegiert diese Befehle dann an den Player. Befehle definiert in Player von Media3 werden automatisch von den Medien Sitzung.

Weitere Informationen finden Sie unter Benutzerdefinierte Befehle hinzufügen. finden Sie eine Anleitung zum Antworten auf einen benutzerdefinierten Befehl.

Verhalten vor Android 13

Aus Gründen der Abwärtskompatibilität bietet die System-UI weiterhin ein alternatives Layout, die Benachrichtigungsaktionen für Apps nutzt, die nicht auf Android 13 aktualisiert werden, oder keine Informationen zu PlaybackState enthalten. Die Aktionsschaltflächen sind abgeleitet aus der Liste Notification.Action, die an MediaStyle angehängt ist Benachrichtigung. Das System zeigt bis zu fünf Aktionen in der Reihenfolge an, in der sie wurden hinzugefügt. Im kompakten Modus werden bis zu drei Schaltflächen angezeigt. Werte, die an setShowActionsInCompactView() übergeben werden.

Benutzerdefinierte Aktionen werden in der Reihenfolge platziert, in der sie zum PlaybackState

Das folgende Codebeispiel zeigt, wie Aktionen zu MediaStyle hinzugefügt werden. Benachrichtigung :

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

Wiederaufnahme von Medien unterstützen

Die Wiederaufnahme von Medien ermöglicht es Nutzern, vorherige Sitzungen aus dem Karussell neu zu starten. ohne die App starten zu müssen. Zu Beginn der Wiedergabe interagiert der Nutzer mit die Mediensteuerung wie gewohnt.

Die Funktion zur Wiederaufnahme der Wiedergabe kann über die App "Einstellungen" aktiviert und deaktiviert werden. unter Ton > Medienoptionen Der Nutzer kann auch folgendermaßen auf die Einstellungen zugreifen: Tippen Sie auf das Zahnradsymbol, das nach dem Wischen über das maximierte Karussell erscheint.

Media3 bietet APIs für eine einfachere Wiederaufnahme von Medien. Weitere Informationen finden Sie in der Wiederaufnahme der Wiedergabe mit Media3 Dokumentation zur Implementierung dieser Funktion.

Legacy-Medien-APIs verwenden

In diesem Abschnitt wird erläutert, wie die Mediensteuerung des Systems mithilfe von der alten MediaCompat-APIs.

Das System ruft die folgenden Informationen aus dem MediaMetadata von MediaSession und zeigt ihn an, wenn er verfügbar ist:

  • METADATA_KEY_ALBUM_ART_URI
  • METADATA_KEY_TITLE
  • METADATA_KEY_DISPLAY_TITLE
  • METADATA_KEY_ARTIST
  • METADATA_KEY_DURATION (Wenn die Dauer nicht festgelegt ist, wird die Steuerleiste nicht Fortschritt anzeigen)

Damit Sie eine gültige und korrekte Benachrichtigung zur Mediensteuerung erhalten, Wert von METADATA_KEY_TITLE oder METADATA_KEY_DISPLAY_TITLE festlegen Metadaten zum Titel der gerade abgespielten Medien.

Im Mediaplayer wird die verstrichene Zeit für die aktuell wiedergegebene Medium, zusammen mit einer Steuerleiste, die der MediaSession PlaybackState.

Der Mediaplayer zeigt den Fortschritt der aktuell wiedergegebenen Medien an. Eine Steuerleiste, die MediaSession PlaybackState zugeordnet ist. Steuerleiste können Nutzer die Position ändern und die verstrichene Zeit für die Medien anzeigen. ein. Um die Suchleiste zu aktivieren, müssen Sie PlaybackState.Builder#setActions und ACTION_SEEK_TO.

Stellen Aktion Kriterien
1 Wiedergeben Der aktuelle Status des PlaybackState ist einer der folgenden: <ph type="x-smartling-placeholder">
    </ph>
  • STATE_NONE
  • STATE_STOPPED
  • STATE_PAUSED
  • STATE_ERROR
Rotierendes Ladesymbol Der aktuelle Status des PlaybackState ist einer der folgenden: <ph type="x-smartling-placeholder">
    </ph>
  • STATE_CONNECTING
  • STATE_BUFFERING
Pausieren Der aktuelle Status von PlaybackState entspricht keinem der oben genannten Werte.
2 Zurück PlaybackState Aktionen umfassen ACTION_SKIP_TO_PREVIOUS.
Benutzerdefiniert PlaybackState Aktionen enthalten ACTION_SKIP_TO_PREVIOUS nicht und PlaybackState benutzerdefinierte Aktionen enthalten eine benutzerdefinierte Aktion, die noch nicht platziert wurde.
Leer PlaybackState-Extras enthalten einen booleschen Wert für true für den Schlüssel SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV.
3 Weiter PlaybackState Aktionen umfassen ACTION_SKIP_TO_NEXT.
Benutzerdefiniert PlaybackState Aktionen enthalten ACTION_SKIP_TO_NEXT nicht und PlaybackState benutzerdefinierte Aktionen enthalten eine benutzerdefinierte Aktion, die noch nicht platziert wurde.
Leer PlaybackState-Extras enthalten einen booleschen Wert für true für den Schlüssel SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT.
4 Benutzerdefiniert PlaybackState benutzerdefinierte Aktionen enthalten eine benutzerdefinierte Aktion, die noch nicht platziert wurde.
5 Benutzerdefiniert PlaybackState benutzerdefinierte Aktionen enthalten eine benutzerdefinierte Aktion, die noch nicht platziert wurde.

Standardaktionen hinzufügen

Die folgenden Codebeispiele veranschaulichen, wie Sie PlaybackState-Standard- und benutzerdefinierten Aktionen.

Für Wiedergabe, Pause, Zurück und Weiter legen Sie diese Aktionen in Den PlaybackState für die Mediensitzung.

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

Sollen für die vorherige oder die nächste Anzeigenfläche keine Schaltflächen angezeigt werden, fügen Sie ACTION_SKIP_TO_PREVIOUS oder ACTION_SKIP_TO_NEXT. Fügen Sie stattdessen Extras zu Sitzung:

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

Benutzerdefinierte Aktionen hinzufügen

Für andere Aktionen, die Sie in den Mediensteuerelementen anzeigen möchten, können Sie ein PlaybackStateCompat.CustomAction und fügen Sie ihn stattdessen dem PlaybackState hinzu. Diese Aktionen werden in der in der sie hinzugefügt wurden.

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

Auf Aktionen für Wiedergabestatus reagieren

Wenn Nutzende auf eine Schaltfläche tippen, verwendet SystemUI MediaController.TransportControls um einen Befehl an MediaSession zurückzusenden. Du musst einen Callback registrieren die entsprechend reagieren können.

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

Medienwiederaufnahme

So sorgst du dafür, dass deine App im Bereich mit den Schnelleinstellungen angezeigt wird: Sie müssen eine MediaStyle-Benachrichtigung mit einem gültigen MediaSession-Token erstellen.

Um den Titel für die MediaStyle-Benachrichtigung anzuzeigen, verwenden Sie NotificationBuilder.setContentTitle()

Um das Markensymbol für den Mediaplayer anzuzeigen, verwenden Sie NotificationBuilder.setSmallIcon()

Apps müssen eine MediaBrowserService implementieren, um die Wiederaufnahme der Wiedergabe zu unterstützen und MediaSession. Dein MediaSession muss den onPlay()-Callback implementieren.

MediaBrowserService-Implementierung

Nach dem Hochfahren sucht das System nach den fünf zuletzt verwendeten Medien. Apps und bietet Steuerelemente, mit denen die Wiedergabe aus jeder App neu gestartet werden kann.

Das System versucht, MediaBrowserService über eine Verbindung von SystemUI Deine App muss solche Verbindungen zulassen, andernfalls unterstützt sie keine Wiedergabe fortgesetzt.

Verbindungen von SystemUI können anhand des Paketnamens identifiziert und verifiziert werden com.android.systemui und Signatur. Die SystemUI ist mit der Plattform signiert. Signatur. Ein Beispiel für den Abgleich mit der Plattformsignatur ist: Sie finden sie in der UAMP App.

Um die Wiederaufnahme der Wiedergabe zu unterstützen, muss dein MediaBrowserService folgende Verhaltensweisen implementieren:

  • onGetRoot() muss schnell einen Stamm ungleich null zurückgeben. Andere komplexe Logik sollte onLoadChildren() bearbeitet werden

  • Wann? onLoadChildren() auf der Stamm-Media-ID aufgerufen wird, muss das Ergebnis einen FLAG_PLAYABLE Kind.

  • MediaBrowserService sollte das zuletzt wiedergegebene Medienelement zurückgeben, wenn erhalten sie eine EXTRA_LETZT Abfrage. Der zurückgegebene Wert sollte ein tatsächliches Medienelement und kein generischer Wert sein. .

  • MediaBrowserService muss eine entsprechende MediaDescription mit einer nicht leeren Beschreibung title und Untertitel. Außerdem sollte ein Symbol-URI oder Bitmap des Symbols.

Die folgenden Codebeispiele veranschaulichen, wie onGetRoot() implementiert wird.

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