Die Mediensteuerung in Android befindet sich in der Nähe der Schnelleinstellungen. Sitzungen aus mehreren Apps sind in einem wischbaren Karussell angeordnet. Im Karussell werden die Sitzungen in dieser Reihenfolge aufgeführt:
- Streams, die lokal auf dem Smartphone wiedergegeben werden
- Remote-Streams, z. B. solche, die auf externen Geräten erkannt wurden, oder Cast-Sitzungen
- Vorherige fortsetzbare Sitzungen in der Reihenfolge, in der sie zuletzt wiedergegeben wurden
Ab Android 13 (API-Level 33) werden Aktionsschaltflächen in der Mediensteuerung aus dem Player Status abgeleitet, damit Nutzer auf eine Vielzahl von Mediensteuerungen für Apps zugreifen können, die Medien wiedergeben.
So können Sie auf allen Geräten eine einheitliche Mediensteuerung und eine optimierte Mediensteuerungsfunktion präsentieren.
Abbildung 1 zeigt ein Beispiel dafür, wie das auf einem Smartphone bzw. Tablet aussieht,
Das System zeigt je nach -Status bis zu fünf Aktionsschaltflächen an, wie
in der folgenden Tabelle beschrieben.Player Im kompakten Modus werden nur die ersten drei Aktions
slots angezeigt. Das entspricht der Darstellung der Mediensteuerung auf anderen
Android-Plattformen wie Auto, Assistant und Wear OS.
| Stellen | Kriterien | Aktion |
|---|---|---|
| 1 |
playWhenReady ist „false“ oder der aktuelle
Wiedergabestatus ist STATE_ENDED.
|
Play |
playWhenReady ist „true“ und der aktuelle
Wiedergabestatus ist STATE_BUFFERING.
|
Rotierendes Ladesymbol | |
playWhenReady ist „true“ und der aktuelle
Wiedergabestatus ist STATE_READY.
|
Pausieren | |
| 2 |
Die Medien
Schaltflächeneinstellungen enthalten eine benutzerdefinierte Schaltfläche für
CommandButton.SLOT_BACK
|
Benutzerdefiniert |
Der Player-Befehl
COMMAND_SEEK_TO_PREVIOUS oder
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM ist verfügbar.
|
Zurück | |
| Es ist weder eine benutzerdefinierte Schaltfläche noch einer der aufgeführten Befehle verfügbar. | Leer | |
| 3 |
Die Einstellungen für Medientasten enthalten eine benutzerdefinierte Schaltfläche für
CommandButton.SLOT_FORWARD
|
Benutzerdefiniert |
Der Player-Befehl
COMMAND_SEEK_TO_NEXT oder
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM ist verfügbar.
|
Weiter | |
| Es ist weder eine benutzerdefinierte Schaltfläche noch einer der aufgeführten Befehle verfügbar. | Leer | |
| 4 |
Die
Einstellungen für Medientasten
enthalten eine benutzerdefinierte Schaltfläche für
CommandButton.SLOT_OVERFLOW die noch nicht platziert wurde.
|
Benutzerdefiniert |
| 5 |
Die
Einstellungen für Medientasten
enthalten eine benutzerdefinierte Schaltfläche für
CommandButton.SLOT_OVERFLOW die noch nicht platziert wurde.
|
Benutzerdefiniert |
Benutzerdefinierte Überlaufschaltflächen werden in der Reihenfolge platziert, in der sie den Einstellungen für Medientasten hinzugefügt wurden.
Befehlsschaltflächen anpassen
Wenn Sie die Mediensteuerung des Systems mit Jetpack Media3 anpassen möchten, können Sie die Einstellungen für Medientasten der Sitzung und die verfügbaren Befehle der Controller entsprechend festlegen:
Erstellen Sie eine
MediaSessionund definieren Sie die Einstellungen für Medientasten für benutzerdefinierte Befehlsschaltflächen.Autorisieren Sie in
MediaSession.Callback.onConnect(), Controller, indem Sie ihre verfügbaren Befehle, einschließlich benutzerdefinierter Befehle, in derConnectionResultdefinieren.Reagieren Sie in
MediaSession.Callback.onCustomCommand(), auf die Auswahl des benutzerdefinierten Befehls durch den Nutzer.
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(CommandButton.ICON_HEART_UNFILLED) .setDisplayName("Save to favorites") .setSessionCommand(customCommandFavorites) .build() val player = ExoPlayer.Builder(this).build() // Build the session with a custom layout. mediaSession = MediaSession.Builder(this, player) .setCallback(MyCallback()) .setMediaButtonPreferences(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) .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(CommandButton.ICON_HEART_UNFILLED) .setDisplayName("Save to favorites") .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()) .setMediaButtonPreferences(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) .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); } } }
Weitere Informationen zum Konfigurieren von MediaSession, damit Clients wie das
System eine Verbindung zu Ihrer Medien-App herstellen können, finden Sie unter
Anderen Clients die Steuerung gewähren.
Wenn Sie mit Jetpack Media3 eine MediaSession implementieren, wird PlaybackState
automatisch mit dem Mediaplayer auf dem neuesten Stand gehalten. Wenn Sie
einen MediaSessionService implementieren, veröffentlicht die Bibliothek automatisch eine
MediaStyle Benachrichtigung
für Sie 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, sendet der
MediaController des Systems einen Wiedergabebefehl an Ihre MediaSession. Die
MediaSession leitet diese Befehle dann an den Player weiter. Befehle
, die in der Player
Schnittstelle von Media3 definiert sind, werden automatisch von der Media
Session verarbeitet.
Unter Benutzerdefinierte Befehle hinzufügen finden Sie eine Anleitung zum Reagieren auf einen benutzerdefinierten Befehl.
Fortsetzung der Medienwiedergabe unterstützen
Mit der Fortsetzung der Medienwiedergabe können Nutzer vorherige Sitzungen über das Karussell neu starten, ohne die App starten zu müssen. Wenn die Wiedergabe beginnt, interagiert der Nutzer wie gewohnt mit der Mediensteuerung.
Die Funktion zur Fortsetzung der Wiedergabe kann in der App „Einstellungen“ unter den Optionen Ton > Medien aktiviert und deaktiviert werden. Der Nutzer kann auch auf die Einstellungen zugriffen, indem er auf das Zahnradsymbol tippt, das nach dem Wischen im erweiterten Karussell angezeigt wird.
Media3 bietet APIs, die die Unterstützung der Fortsetzung der Medienwiedergabe erleichtern. Eine Anleitung zur Implementierung dieser Funktion finden Sie in der Dokumentation zur Fortsetzung der Wiedergabe mit Media3.
Legacy-Media-APIs verwenden
In diesem Abschnitt wird beschrieben, wie Sie die Mediensteuerung des Systems mit den Legacy-MediaCompat-APIs einbinden.
Das System ruft die folgenden Informationen aus den
MediaSession's MediaMetadata ab und zeigt sie an, wenn sie verfügbar sind:
METADATA_KEY_ALBUM_ART_URIMETADATA_KEY_TITLEMETADATA_KEY_DISPLAY_TITLEMETADATA_KEY_ARTISTMETADATA_KEY_DURATION(Wenn die Dauer nicht festgelegt ist, wird der Fortschritt nicht auf der Suchleiste angezeigt )
Damit Sie eine gültige und genaue Benachrichtigung zur Mediensteuerung erhalten,
legen Sie den Wert der METADATA_KEY_TITLE oder METADATA_KEY_DISPLAY_TITLE
Metadaten auf den Titel der aktuell wiedergegebenen Medien fest.
Der Mediaplayer zeigt die verstrichene Zeit für die aktuell wiedergegebenen
Medien sowie eine Suchleiste an, die MediaSession
PlaybackState zugeordnet ist.
Der Mediaplayer zeigt den Fortschritt für die aktuell wiedergegebenen Medien sowie
eine Suchleiste an, die MediaSession PlaybackState zugeordnet ist. Über die Suchleiste
können Nutzer die Position ändern und die verstrichene Zeit für das Medien
element anzeigen. Damit die Suchleiste aktiviert werden kann, müssen Sie
PlaybackState.Builder#setActions implementieren und ACTION_SEEK_TO einfügen.
| Stellen | Aktion | Kriterien |
|---|---|---|
| 1 | Play |
Der aktuelle Status von PlaybackState ist einer der folgenden:
|
| Rotierendes Ladesymbol |
Der aktuelle Status von PlaybackState ist einer der folgenden:
|
|
| Pausieren | Der aktuelle Status von PlaybackState ist keiner der oben genannten. |
|
| 2 | Zurück | PlaybackState Aktionen enthalten ACTION_SKIP_TO_PREVIOUS. |
| Benutzerdefiniert | PlaybackState Aktionen enthalten nicht ACTION_SKIP_TO_PREVIOUS und PlaybackState benutzerdefinierte Aktionen enthalten eine benutzerdefinierte Aktion, die noch nicht platziert wurde. |
|
| Leer | PlaybackState Extras enthalten einen booleschen Wert true für den Schlüssel SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV. |
|
| 3 | Weiter | PlaybackState Aktionen enthalten ACTION_SKIP_TO_NEXT. |
| Benutzerdefiniert | PlaybackState Aktionen enthalten nicht ACTION_SKIP_TO_NEXT und PlaybackState benutzerdefinierte Aktionen enthalten eine benutzerdefinierte Aktion, die noch nicht platziert wurde. |
|
| Leer | PlaybackState Extras enthalten einen booleschen Wert für den Schlüssel SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT.true |
|
| 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 zeigen, wie Sie PlaybackState Standard- und
benutzerdefinierte Aktionen hinzufügen.
Legen Sie für „Play“, „Pause“, „Zurück“ und „Weiter“ diese Aktionen in
der PlaybackState für die Media Session fest.
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);
Wenn Sie keine Schaltflächen in den Slots „Zurück“ oder „Weiter“ möchten, fügen Sie nicht
ACTION_SKIP_TO_PREVIOUS oder ACTION_SKIP_TO_NEXT, sondern stattdessen Extras zu
der Sitzung hinzu:
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 in der Mediensteuerung angezeigt werden sollen, können Sie stattdessen eine
PlaybackStateCompat.CustomAction
erstellen und sie zu PlaybackState hinzufügen. Diese Aktionen werden in der
Reihenfolge angezeigt, 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 PlaybackState-Aktionen reagieren
Wenn ein Nutzer auf eine Schaltfläche tippt, sendet SystemUI mit
MediaController.TransportControls
einen Befehl an die MediaSession zurück. Sie müssen einen Callback
registrieren, der ordnungsgemäß auf diese Ereignisse reagieren kann.
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); } } };
Fortsetzung der Medienwiedergabe
Damit Ihre Player-App im Bereich der Schnelleinstellungen angezeigt wird,
müssen Sie eine MediaStyle-Benachrichtigung mit einem gültigen MediaSession-Token erstellen.
Verwenden Sie
NotificationBuilder.setContentTitle(), um den Titel für die MediaStyle-Benachrichtigung anzuzeigen.
Verwenden Sie
NotificationBuilder.setSmallIcon(), um das Markensymbol für den Mediaplayer anzuzeigen.
Um die Fortsetzung der Wiedergabe zu unterstützen, müssen Apps einen MediaBrowserService
und MediaSession implementieren. Ihre MediaSession muss den onPlay() Callback implementieren.
MediaBrowserService-Implementierung
Nach dem Start des Geräts sucht das System nach den fünf zuletzt verwendeten Medien Apps und bietet Steuerelemente, mit denen die Wiedergabe in jeder App neu gestartet werden kann.
Das System versucht, mit einer Verbindung von
SystemUI aus Ihren MediaBrowserService zu kontaktieren. Ihre App muss solche Verbindungen zulassen, andernfalls kann sie die Fortsetzung der Wiedergabe nicht unterstützen.
Verbindungen von SystemUI können anhand des Paketnamens
com.android.systemui und der Signatur identifiziert und überprüft werden. SystemUI ist mit der Plattform
signatur signiert. Ein Beispiel dafür, wie Sie die Plattformsignatur prüfen können, finden Sie in der UAMP-App.
Damit die Fortsetzung der Wiedergabe unterstützt werden kann, muss Ihr MediaBrowserService diese Verhaltensweisen
implementieren:
onGetRoot()muss schnell einen Root-Wert zurückgeben, der nicht null ist. Andere komplexe Logik sollte inonLoadChildren()verarbeitet werden.Wenn
onLoadChildren()für die Root-Medien-ID aufgerufen wird, muss das Ergebnis ein FLAG_PLAYABLE untergeordnetes Element enthalten.MediaBrowserServicesollte das zuletzt wiedergegebene Medienelement zurückgeben, wenn eine EXTRA_RECENT Abfrage empfangen wird. Der zurückgegebene Wert sollte ein tatsächliches Medienelement und keine generische Funktion sein.MediaBrowserServicemuss eine geeignete MediaDescription mit einem nicht leeren Titel und Untertitel bereitstellen. Außerdem sollte ein Symbol-URI oder eine Symbol-Bitmapfestgelegt werden.
Die folgenden Codebeispiele zeigen, wie Sie onGetRoot() implementieren.
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); }
Verhalten vor Android 13
Aus Gründen der Abwärtskompatibilität bietet die System-UI weiterhin ein alternatives Layout, das Benachrichtigungsaktionen für Apps verwendet, die nicht auf Android 13 aktualisiert werden
oder keine PlaybackState Informationen enthalten. Die Aktionsschaltflächen werden
aus der Notification.Action-Liste abgeleitet, die an die MediaStyle
Benachrichtigung angehängt ist. Das System zeigt bis zu fünf Aktionen in der Reihenfolge an, in der sie
hinzugefügt wurden. Im kompakten Modus werden bis zu drei Schaltflächen angezeigt, die durch die
an
setShowActionsInCompactView() übergebenen Werte bestimmt werden.
Benutzerdefinierte Aktionen werden in der Reihenfolge platziert, in der sie zu der
PlaybackState hinzugefügt wurden.
Das folgende Codebeispiel zeigt, wie Sie der MediaStyle Benachrichtigung Aktionen hinzufügen :
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) // 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(new MediaStyleNotificationHelper.MediaStyle(mediaSession) .setShowActionsInCompactView(1 /* #1: pause button */)) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build();