Auf Medienschaltflächen reagieren

Medientasten sind Hardwaretasten auf Android-Geräten und anderen Peripheriegeräten, z. B. die Pause-/Wiedergabe-Taste an einem Bluetooth-Headset. Wenn ein Nutzer eine Medienschaltfläche drückt, generiert Android eine KeyEvent, die einen Schlüsselcode zur Identifizierung der Schaltfläche enthält. Die Schlüsselcodes für Medienschaltflächen-KeyEvents sind Konstanten, die mit KEYCODE_MEDIA beginnen (z. B. KEYCODE_MEDIA_PLAY).

Apps sollten Medienschaltflächenereignisse in drei Fällen verarbeiten können – in der folgenden Prioritätsreihenfolge:

  • Wenn die UI-Aktivität der App sichtbar ist
  • Wenn die UI-Aktivität ausgeblendet ist und die Mediensitzung der App aktiv ist
  • Wenn die UI-Aktivität ausgeblendet ist und die Mediensitzung der App inaktiv ist und neu gestartet werden muss

Umgang mit Medienschaltflächen bei einer Aktivität im Vordergrund

Die Vordergrundaktivität empfängt das Schlüsselereignis für die Medienschaltfläche in ihrer onKeyDown()-Methode. Je nach verwendeter Android-Version gibt es zwei Möglichkeiten, wie das System das Ereignis an einen Mediencontroller weiterleitet:

  • Wenn du Android 5.0 (API-Level 21) oder höher verwendest, rufe FLAG_HANDLES_MEDIA_BUTTONS MediaBrowserCompat.ConnectionCallback.onConnected auf. Dadurch wird automatisch dispatchMediaButtonEvent() des Mediencontrollers aufgerufen, der den Schlüsselcode in einen Mediensitzungs-Callback übersetzt.
  • Vor Android 5.0 (API-Level 21) musst du onKeyDown() so ändern, dass das Ereignis selbst verarbeitet wird. Weitere Informationen finden Sie unter Handhabung von Medienschaltflächen in einer aktiven Mediensitzung. Das folgende Code-Snippet zeigt, wie der Schlüsselcode abgefangen und dispatchMediaButtonEvent() aufgerufen wird. Geben Sie true zurück, um anzugeben, dass das Ereignis verarbeitet wurde:

    Kotlin

        fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                return super.onKeyDown(keyCode, event)
            }
            when (keyCode) {
                KeyEvent.KEYCODE_MEDIA_PLAY -> {
                    yourMediaController.dispatchMediaButtonEvent(event)
                    return true
                }
            }
            return super.onKeyDown(keyCode, event)
        }
        

    Java

        @Override
        boolean onKeyDown(int keyCode, KeyEvent event) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                  return super.onKeyDown(keyCode, event);
                }
                switch (keyCode) {
                  case KeyEvent.KEYCODE_MEDIA_PLAY:
                          yourMediaController.dispatchMediaButtonEvent(event);
                          return true;
                }
                return super.onKeyDown(keyCode, event);
        }
        

Mediensitzung finden

Wenn die Aktivität im Vordergrund das Ereignis nicht verarbeitet, versucht Android, eine Mediensitzung zu finden, die es verarbeiten kann. Auch hier gibt es je nach verwendeter Android-Version zwei Möglichkeiten, nach einer Mediensitzung zu suchen:

  • Wenn Sie Android 8.0 (API-Level 26) oder höher ausführen, versucht das System, die letzte App mit einer MediaSession zu finden, die Audioinhalte lokal wiedergegeben hat. Wenn die Sitzung noch aktiv ist, sendet Android das Ereignis direkt an sie. Wenn die Sitzung nicht aktiv ist und über einen Mediabutton-Empfänger verfügt, sendet Android das Ereignis an den Empfänger. Dieser startet die Sitzung neu und kann das Ereignis empfangen. Weitere Informationen finden Sie unter Medienschaltflächen zum Neustart einer inaktiven Mediensitzung verwenden. Wenn die Sitzung keinen Medienschaltflächenempfänger hat, verwirft das System das Medienschaltflächenereignis und nichts passiert. Die Logik wird im folgenden Diagramm dargestellt:

  • Vor Android 8.0 (API-Level 26) versucht das System, das Ereignis an eine aktive Mediensitzung zu senden. Gibt es mehrere aktive Mediensitzungen, versucht Android, statt einer angehaltenen Mediensitzung eine Mediensitzung auszuwählen, die zur Wiedergabe vorbereitet (zwischengespeichert/verbunden), noch abgespielt oder pausiert wird. Weitere Informationen finden Sie unter Medienschaltflächen in einer aktiven Mediensitzung verarbeiten. Wenn keine aktive Sitzung vorhanden ist, versucht Android, das Ereignis an die zuletzt aktive Sitzung zu senden. Weitere Informationen finden Sie unter Medienschaltflächen zum Neustart einer inaktiven Mediensitzung verwenden. Die Logik wird im folgenden Diagramm dargestellt:

Umgang mit Medienschaltflächen in einer aktiven Mediensitzung

Unter Android 5.0 (API-Level 21) und höher sendet Android automatisch Medienschaltflächenereignisse an deine aktive Mediensitzung durch den Aufruf von onMediaButtonEvent(). Standardmäßig übersetzt dieser Callback das KeyEvent in die entsprechende Callback-Methode für Mediensitzungen, die dem Schlüsselcode entspricht.

Vor Android 5.0 (API-Level 21) verarbeitet Android Medienschaltflächenereignisse, indem es einen Intent mit der Aktion ACTION_MEDIA_BUTTON sendet. Deine App muss einen BroadcastReceiver registrieren, um diese Intents abzufangen. Die Klasse MediaButtonReceiver wurde speziell für diesen Zweck entwickelt. Dabei handelt es sich um eine Convenience-Klasse in der Android-Medienkompatibilitätsbibliothek, die ACTION_MEDIA_BUTTON verarbeitet und die eingehenden Intents in die entsprechenden MediaSessionCompat.Callback-Methodenaufrufe umwandelt.

Ein MediaButtonReceiver ist ein kurzlebiger BroadcastReceiver. Er leitet eingehende Intents an den Dienst weiter, der Ihre Mediensitzung verwaltet. Wenn Sie Medienschaltflächen in Systemen vor Android 5.0 verwenden möchten, müssen Sie MediaButtonReceiver in Ihr Manifest mit einem MEDIA_BUTTON-Intent-Filter aufnehmen.:

<receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
   <intent-filter>
     <action android:name="android.intent.action.MEDIA_BUTTON" />
   </intent-filter>
 </receiver>

BroadcastReceiver leitet den Intent an Ihren Dienst weiter. Um den Intent zu parsen und den Callback für Ihre Mediensitzung zu generieren, fügen Sie die Methode MediaButtonReceiver.handleIntent() in die onStartCommand() Ihres Dienstes ein. Dadurch wird der Schlüsselcode in die entsprechende Sitzungs-Callback-Methode übersetzt.

Kotlin

private val mediaSessionCompat: MediaSessionCompat = ...

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    MediaButtonReceiver.handleIntent(mediaSessionCompat, intent)
    return super.onStartCommand(intent, flags, startId)
}

Java

private MediaSessionCompat mediaSessionCompat = ...;

 public int onStartCommand(Intent intent, int flags, int startId) {
   MediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
   return super.onStartCommand(intent, flags, startId);
 }

Mit Medientasten eine inaktive Mediensitzung neu starten

Wenn Android die letzte aktive Mediensitzung identifizieren kann, versucht es, die Sitzung neu zu starten. Dazu wird ein ACTION_MEDIA_BUTTON-Intent an eine Manifest-registrierte Komponente gesendet (z. B. einen Dienst oder BroadcastReceiver).

So kann die App die Wiedergabe neu starten, während die Benutzeroberfläche nicht sichtbar ist. Das ist bei den meisten Audio-Apps der Fall.

Dieses Verhalten wird automatisch aktiviert, wenn Sie MediaSessionCompat verwenden. Wenn Sie das MediaSession-Framework der Android-Framework oder die Support Library 24.0.0 bis 25.1.1 verwenden, müssen Sie setMediaButtonReceiver aufrufen, damit eine inaktive Mediensitzung über eine Medienschaltfläche neu gestartet wird.

Sie können dieses Verhalten unter Android 5.0 (API-Level 21) und höher deaktivieren, indem Sie einen Null-Medienschaltflächenempfänger festlegen:

Kotlin

// Create a MediaSessionCompat
mediaSession = MediaSessionCompat(context, LOG_TAG)
mediaSession.setMediaButtonReceiver(null)

Java

// Create a MediaSessionCompat
mediaSession = new MediaSessionCompat(context, LOG_TAG);
mediaSession.setMediaButtonReceiver(null);

Handler für Medienschaltflächen anpassen

Beim Standardverhalten für onMediaButtonEvent() wird der Schlüsselcode extrahiert und anhand des aktuellen Status der Mediensitzung und der Liste der unterstützten Aktionen ermittelt, welche Methode aufgerufen wird. Beispielsweise ruft KEYCODE_MEDIA_PLAY onPlay() auf.

Damit Medienschaltflächen in allen Apps einheitlich funktionieren, sollten Sie das Standardverhalten verwenden und nur für einen bestimmten Zweck davon abweichen. Wenn eine Medienschaltfläche benutzerdefinierte Verarbeitung erfordert, überschreiben Sie die Methode onMediaButtonEvent() des Callbacks, extrahieren Sie KeyEvent mit intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT), verarbeiten Sie das Ereignis selbst und geben Sie true zurück.

Zusammenfassung

Damit Medienschaltflächenereignisse in allen Android-Versionen richtig verarbeitet werden, müssen Sie beim Erstellen einer Mediensitzung FLAG_HANDLES_MEDIA_BUTTONS angeben.

Abhängig von den Android-Versionen, die Sie unterstützen möchten, müssen Sie außerdem die folgenden Anforderungen erfüllen:

Unter Android 5.0 oder höher:

  • MediaControllerCompat.setMediaController() über den onConnected()-Callback der Mediensteuerung aufrufen
  • Wenn Sie über eine Medienschaltfläche den Neustart einer inaktiven Sitzung zulassen möchten, erstellen Sie dynamisch einen MediaButtonReceiver, indem Sie setMediaButtonReceiver() aufrufen und ein PendingIntent übergeben.

Bei Ausführung in Systemen vor Android 5.0:

  • Die onKeyDown() der Aktivität für die Verarbeitung von Medienschaltflächen überschreiben
  • MediaButtonReceiver durch Hinzufügen zum Manifest der App statisch erstellen