Reakcja na przyciski multimediów

Przyciski multimediów to przyciski sprzętowe dostępne na urządzeniach z Androidem i innych urządzeniach peryferyjnych, np. przycisk wstrzymania/odtwarzania w zestawie słuchawkowym Bluetooth. Gdy użytkownik kliknie przycisk multimediów, Android generuje kod KeyEvent zawierający kod klucza, który identyfikuje ten przycisk. Kody kluczy zdarzeń KeyEvents przycisku mediów są stałymi zaczynającymi się od KEYCODE_MEDIA (np. KEYCODE_MEDIA_PLAY).

Aplikacje powinny obsługiwać zdarzenia przycisków multimediów w 3 przypadkach, w tej kolejności według priorytetu:

  • Gdy aktywność w interfejsie użytkownika jest widoczna
  • Gdy aktywność w interfejsie jest ukryta, a sesja multimediów w aplikacji jest aktywna
  • Gdy aktywność w interfejsie jest ukryta, a sesja multimediów w aplikacji jest nieaktywna i wymaga ponownego uruchomienia

Obsługa przycisków multimediów w aktywności na pierwszym planie

Aktywność na pierwszym planie odbiera w metodzie onKeyDown() zdarzenie klucza multimediów. W zależności od używanej wersji Androida system może kierować zdarzenie do kontrolera multimediów na 2 sposoby:

  • Jeśli używasz Androida 5.0 (poziom interfejsu API 21) lub nowszego, wywołaj metodę FLAG_HANDLES_MEDIA_BUTTONS MediaBrowserCompat.ConnectionCallback.onConnected. Spowoduje to automatyczne wywołanie funkcji dispatchMediaButtonEvent() kontrolera multimediów, która przekształci kod klucza na wywołanie zwrotne sesji multimediów.
  • W wersjach starszych niż 5.0 (poziom interfejsu API 21) musisz zmodyfikować onKeyDown(), aby samodzielnie obsługiwał zdarzenie. (więcej informacji znajdziesz w sekcji Obsługa przycisków multimediów w aktywnej sesji multimediów). Poniższy fragment kodu pokazuje, jak przechwycić kod klucza i wywołać metodę dispatchMediaButtonEvent(). Pamiętaj, aby zwrócić true, aby wskazać, że zdarzenie zostało przetworzone:

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

Szukam sesji multimediów

Jeśli aktywność na pierwszym planie nie obsługuje danego zdarzenia, Android spróbuje znaleźć sesję multimediów, która to umożliwia. W zależności od wersji Androida są dwa sposoby wyszukiwania sesji multimediów:

  • Jeśli używasz Androida 8.0 (poziom interfejsu API 26) lub nowszego, system próbuje znaleźć ostatnią aplikację z funkcją MediaSession, która odtwarzała dźwięk lokalnie. Jeśli sesja jest nadal aktywna, Android wysyła zdarzenie bezpośrednio do niej. W przeciwnym razie, jeśli sesja jest nieaktywna i ma odbiornik mediabutton, Android wysyła zdarzenie do odbiornika, co spowoduje ponowne uruchomienie sesji i jej odebranie. (Szczegółowe informacje znajdziesz w artykule Ponowne uruchamianie nieaktywnej sesji multimediów przy użyciu przycisków multimediów). Jeśli sesja nie ma odbiornika przycisku multimediów, system odrzuca zdarzenie przycisku multimediów i nic się nie dzieje. Logika ta jest przedstawiona na tym diagramie:

  • W wersjach starszych niż 8.0 (poziom interfejsu API 26) system próbuje wysłać zdarzenie do aktywnej sesji multimediów. Jeśli jest wiele aktywnych sesji multimediów, Android próbuje wybrać taką, która jest przygotowywana do odtwarzania (buforowania/łączenia), odtwarzana lub wstrzymana, a nie zatrzymana. Więcej informacji znajdziesz w sekcji Obsługa przycisków multimediów w aktywnej sesji multimediów. Jeśli nie ma aktywnej sesji, Android próbuje wysłać zdarzenie do ostatnio aktywnej sesji. (Szczegółowe informacje znajdziesz w artykule Ponowne uruchamianie nieaktywnej sesji multimediów przy użyciu przycisków multimediów). Logika ta została przedstawiona na tym diagramie:

Obsługa przycisków multimediów w aktywnej sesji multimediów

Na Androidzie 5.0 (poziom interfejsu API 21) i nowszych Android automatycznie wysyła zdarzenia przycisków multimediów do aktywnej sesji multimediów, wywołując onMediaButtonEvent(). Domyślnie to wywołanie zwrotne przekształca zdarzenie KeyEvent na odpowiednią metodę wywołania zwrotnego sesji multimedialnej, która pasuje do kodu klucza.

Przed Androidem 5.0 (poziom interfejsu API 21) Android obsługuje zdarzenia przycisków multimediów, transmitując intencję z działaniem ACTION_MEDIA_BUTTON. Aby przechwycić te intencje, aplikacja musi zarejestrować obiekt BroadcastOdbieranier. Zajęcia MediaButtonReceiver zostały zaprojektowane właśnie w tym celu. Jest to klasa wygodna w bibliotece media-compat Androida, która obsługuje ACTION_MEDIA_BUTTON i tłumaczy przychodzące intencje na odpowiednie wywołania metody MediaSessionCompat.Callback.

MediaButtonReceiver to działający przez krótki czas Broadcastodbiornik. Przekazuje ona zamiary przychodzące do usługi, która zarządza Twoją sesją multimediów. Jeśli chcesz używać przycisków multimediów w systemach starszych niż Android 5.0, musisz uwzględnić w pliku manifestu parametr MediaButtonReceiver z filtrem intencji MEDIA_BUTTON.

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

BroadcastReceiver przekazuje intencję do Twojej usługi. Aby przeanalizować intencję i wygenerować wywołanie zwrotne do sesji multimediów, umieść metodę MediaButtonReceiver.handleIntent() w pliku onStartCommand() usługi. W ten sposób kod klucza zostanie przekształcony w odpowiednią metodę wywołania zwrotnego sesji.

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

Używanie przycisków multimediów do ponownego uruchamiania nieaktywnej sesji multimediów

Jeśli Android jest w stanie zidentyfikować ostatnią aktywną sesję multimediów, próbuje zrestartować sesję, wysyłając intencję ACTION_MEDIA_BUTTON do komponentu zarejestrowanego w pliku manifestu (np. usługi lub BroadcastReceiver).

Dzięki temu aplikacja może ponownie uruchomić odtwarzanie, gdy jej interfejs nie jest widoczny. Tak dzieje się w przypadku większości aplikacji audio.

To zachowanie jest automatycznie włączone, gdy używasz MediaSessionCompat. Jeśli używasz pakietu MediaSession platformy Android lub biblioteki pomocy technicznej od 24.0.0 do 25.1.1, musisz wywołać metodę setMediaButtonReceiver, aby przycisk multimediów mógł ponownie uruchomić nieaktywne sesje multimediów.

Możesz wyłączyć to działanie w Androidzie 5.0 (poziom interfejsu API 21) i nowszych, ustawiając odbiornik przycisku multimedialnego o wartości null:

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

Dostosowywanie modułów obsługi przycisków multimediów

Domyślne działanie onMediaButtonEvent() wyodrębnia kod klucza i określa, którą metodę wywołać, na podstawie bieżącego stanu sesji multimediów i listy obsługiwanych działań. Na przykład KEYCODE_MEDIA_PLAY wywołuje metodę onPlay().

Aby przyciski multimediów działały tak samo we wszystkich aplikacjach, używaj działania domyślnego i zmieniaj ustawienia tylko w konkretnym celu. Jeśli przycisk multimediów wymaga niestandardowej obsługi, zastąp metodę onMediaButtonEvent() wywołania zwrotnego, wyodrębnij parametr KeyEvent za pomocą intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT), przygotuj zdarzenie samodzielnie i zwróć true.

Podsumowanie

Aby prawidłowo obsługiwać zdarzenia przycisków multimediów we wszystkich wersjach Androida, podczas tworzenia sesji multimediów musisz określić FLAG_HANDLES_MEDIA_BUTTONS.

Dodatkowo w zależności od wersji Androida, które mają być obsługiwane, musisz też spełniać te wymagania:

Jeśli korzystasz z Androida w wersji 5.0 lub nowszej:

  • Wywołaj MediaControllerCompat.setMediaController() z kontrolera multimediów przez wywołanie zwrotne onConnected()
  • Aby umożliwić przyciskowi multimediów ponowne uruchomienie nieaktywnej sesji, utwórz dynamicznie obiekt MediaButtonReceiver, wywołując metodę setMediaButtonReceiver() i przekazując mu PendingIntent

Jeśli korzystasz z systemu w systemie starszym niż Android 5.0:

  • Aby obsługiwać przyciski multimediów, zastąp parametr onKeyDown() aktywności
  • Statycznie utwórz obiekt MediaButtonReceiver, dodając go do pliku manifestu aplikacji.