Zarządzaj aktywnością audio

Co najmniej 2 aplikacje na Androida mogą odtwarzać dźwięk w tym samym strumieniu wyjściowym jednocześnie, a system łączy wszystko w jedną całość. Choć jest to imponujące technicznie może być dla użytkownika bardzo przykre. Aby uniknąć: w tym samym czasie odtwarzania aplikacji muzycznych, Android wprowadza pomysł dźwięku. skupienie. Tylko jedna aplikacja może utrzymywać skupienie dźwięku w danym momencie.

Gdy aplikacja musi odtwarzać dźwięk, powinna zażądać fokusu audio. Kiedy zostanie może odtwarzać dźwięk. Po uzyskaniu ostrości dźwięku można jednak który możesz przechowywać, aż skończysz grać. Inna aplikacja może poprosić o koncentrację, zapobiega skupieniu się na dźwięku. W takim przypadku aplikacja powinna zostać wstrzymana włącza lub zmniejsza głośność, aby użytkownicy mogli lepiej słyszeć nowe źródło dźwięku.

W starszych wersjach Androida 12 (poziom interfejsu API 31) system nie zarządza aktywnością audio. A więc, zachęcamy deweloperów aplikacji do stosowania się do wytycznych dotyczących skupienia na dźwięku, jeśli aplikacja nadal gra głośno nawet po utracie ostrości audio na urządzeniu; z Androidem 11 (poziom interfejsu API 30) lub niższym, system nie może temu zapobiec. Takie działanie aplikacji negatywnie wpływa jednak na wrażenia użytkowników i często prowadzi odinstalowanie wadliwej aplikacji.

Dobrze zaprojektowana aplikacja audio powinna zarządzać ostrością audio zgodnie z wytycznymi:

  • Zadzwoń pod numer requestAudioFocus() tuż przed rozpoczęciem gry i sprawdź, czy połączenie zostanie przywrócone AUDIOFOCUS_REQUEST_GRANTED Zadzwoń do requestAudioFocus() w wywołaniu zwrotnym onPlay() sesji multimediów.

  • Gdy inna aplikacja uzyska ostrość dźwięku, zatrzyma lub wstrzyma odtwarzanie albo wycisz (czyli zmniejsz głośność).

  • Po zatrzymaniu odtwarzania (np. gdy w aplikacji nie ma nic do odtworzenia) porzucić aktywność audio. Aplikacja nie musi rezygnować z fokusu, jeśli użytkownik wstrzyma odtwarzanie, ale może wznowić je później.

  • Użyj AudioAttributes, aby opisać typu audio odtwarzanej przez aplikację. Na przykład w przypadku aplikacji, które odtwarzają mowę, określ CONTENT_TYPE_SPEECH

Obsługa dźwięku różni się w zależności od wersji Androida jest uruchomiony:

Android 12 (poziom interfejsu API 31) lub nowszy
Koncentracja dźwięku jest zarządzana przez system. System wymusza odtwarzanie dźwięku aplikacja ma zanikać, gdy inna aplikacja poprosi o tryb audio. System wycisza też odtwarzanie dźwięku po nadejściu połączenia.
Android od 8.0 (poziom interfejsu API 26) do Androida 11 (poziom interfejsu API 30)
System dźwięku nie zarządza ustawieniami dźwięku, ale zawiera zmiany, które zostały wprowadzone w Androidzie 8.0 (poziom interfejsu API 26).
Android 7.1 (poziom interfejsu API 25) lub niższy
System dźwięku nie jest zarządzany dźwiękiem, a aplikacje zarządzają skupieniem na dźwięku za pomocą requestAudioFocus() oraz abandonAudioFocus()

Aktywność audio na Androidzie 12 i nowszych

Aplikacja do multimediów lub gry, która wykorzystuje aktywność audio, nie powinna odtwarzać dźwięku, gdy zostanie utracony ostrość. W Androidzie 12 (poziom interfejsu API 31) i nowszych wersjach system wymusza to zachowanie użytkownika. Gdy aplikacja prosi o aktywację dźwięku, a inna aplikacja jest zaznaczona podczas odtwarzania, system wymusza wyciszenie odtwarzanej aplikacji. Dodanie funkcji pozwala płynniej przechodzić między aplikacjami.

Efekt zanikania ma miejsce, gdy są spełnione te warunki:

  1. Pierwsza odtwarzana aplikacja spełnia wszystkie te kryteria:

  2. Druga aplikacja prosi o fokus za pomocą funkcji AudioManager.AUDIOFOCUS_GAIN.

Po spełnieniu tych warunków system audio w pierwszej aplikacji wyciszy dźwięk. Na do końca zanikania, system powiadamia pierwszą aplikację o utracie ostrości. Parametr aplikacji odtwarzacze pozostaną wyciszone, dopóki aplikacja nie zażąda ponownego skupienia się na dźwięku.

Dotychczasowe zachowania skupienia względem dźwięku

Musisz też pamiętać o innych przypadkach, które wiążą się ze zmianą dźwięku. ostrość.

Automatyczne wyciszanie

automatyczne wyciszanie (tymczasowe obniżenie poziomu dźwięku w jednej aplikacji, innego wyraźnie słychać) został wprowadzony w Androidzie 8.0 (poziom API 26).

Dzięki wdrożeniu przez system funkcji wyciszania tła nie trzeba do aplikacji.

Automatyczne wyciszanie tła pojawia się też wtedy, gdy powiadomienie dźwiękowe przyciąga uwagę w aplikacji z grafiką. Początek odtwarzania powiadomienia jest zsynchronizowany na końcu rampy ścigającej się.

Automatyczne wyciszanie ma miejsce, gdy są spełnione te warunki:

  1. Pierwsza odtwarzana aplikacja spełnia wszystkie te kryteria:

  2. Druga aplikacja prosi o aktywowanie dźwięku za pomocą: AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK

Gdy te warunki są spełnione, system audio duplikuje wszystkie aktywne odtwarzacze jest ustawiona na pierwszą aplikację, podczas gdy druga jest zaznaczony. Gdy druga aplikacja przestanie działać i usuwają koncentrację. Pierwsza aplikacja nie jest powiadamiana, gdy straci ważność, więc nie trzeba nic robić.

Pamiętaj, że automatyczne wyciszanie nie działa, gdy użytkownik słucha utworu treści głosowych, ponieważ użytkownik może ominąć część programu. Przykład: wskazówki głosowe dotyczące wskazówek dojazdu nie są wyciszone.

Wycisz bieżące odtwarzanie dźwięku przychodzących połączeń telefonicznych

Niektóre aplikacje działają nieprawidłowo i nadal odtwarzają dźwięk podczas rozmów telefonicznych. Użytkownik musi wtedy znaleźć i wyciszyć lub zamknąć problematyczną aplikację w aby usłyszeć jego połączenie. Aby temu zapobiec, system może wyciszyć dźwięk z innych aplikacji podczas połączenia przychodzącego. System wywołuje tę funkcję, gdy odebrane połączenie telefoniczne, a aplikacja spełnia te warunki:

  • Aplikacja ma AudioAttributes.USAGE_MEDIA lub Atrybut wykorzystania AudioAttributes.USAGE_GAME.
  • Aplikacja zażądała aktywności audio (dowolne wzmocnienie ostrości) i jest odtwarzana audio.

Jeśli w trakcie rozmowy aplikacja będzie nadal odtwarzać treści, jej odtwarzanie zostanie wyciszone do czasu zakończono połączenie. Jeśli jednak aplikacja zacznie grać w trakcie rozmowy, nie będzie wyciszono przy założeniu, że użytkownik rozpoczął odtwarzanie celowo.

Skupienie na dźwięku na Androidzie w wersji od 8.0 do 11

Począwszy od Androida 8.0 (poziom interfejsu API 26), gdy wywołujesz requestAudioFocus() musisz podać parametr AudioFocusRequest. AudioFocusRequest zawiera informacje o kontekście audio i możliwościach aplikacji. system wykorzystuje te informacje do zarządzania wzmocnieniem i utratą ostrości audio automatycznie. Aby zwolnić aktywność audio, wywołaj metodę abandonAudioFocusRequest() który również przyjmuje AudioFocusRequest jako argument. Użyj tego samego AudioFocusRequest zarówno po wysłaniu żądania, jak i porzuceniu fokusu.

Aby utworzyć AudioFocusRequest, użyj AudioFocusRequest.Builder Ponieważ prośba o fokus musi zawsze określaj typ żądania, typ jest zawarty w konstruktorze dla konstruktora. Użyj metod kreatora, aby ustawić pozostałe pola wartości użytkownika.

Pole FocusGain jest wymagane. Wszystkie pozostałe pola są opcjonalne.

MetodaUwagi
setFocusGain() To pole jest wymagane w każdym żądaniu. Przyjmuje takie same wartości, jak durationHint używane w wywołaniu requestAudioFocus() w systemie starszym niż Android 8.0: AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, czy AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE.
setAudioAttributes() AudioAttributes opisuje przypadek użycia Twojej aplikacji. system na nie patrzy, gdy aplikacja zyskuje i utraca ostrość obrazu. Atrybuty pozwalają zastąpić pojęcie typu strumieniowania. W Androidzie 8.0 (poziom interfejsu API 26) i nowszych typy strumieniowania na potrzeby operacji innych niż sterowanie głośnością zostały wycofane. Używaj te same atrybuty w żądaniu fokusu, których używasz w odtwarzaczu dźwięku (jak w przykładzie poniżej tabeli).

Użyj AudioAttributes.Builder, aby określić a następnie za pomocą tej metody przypisz atrybuty do użytkownika.

Jeśli nie określono tej wartości, AudioAttributes przyjmuje domyślnie wartość AudioAttributes.USAGE_MEDIA.

setWillPauseWhenDucked() Gdy inna aplikacja prosi o skupienie się na AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, aktywna aplikacja nie zwykle otrzymują onAudioFocusChange() ponieważ system może wykonać lub ukrycie się. Gdy musisz wstrzymać odtwarzanie, a nie niż zmniejszyć głośność, wywołaj setWillPauseWhenDucked(true), utwórz i ustaw OnAudioFocusChangeListener, zgodnie z opisem w sekcji automatycznej ukrywanie uczuć.
setAcceptsDelayedFocusGain() Żądanie aktywności audio może się nie powieść, gdy zaznaczenie jest zablokowane przez inną aplikację. Ta metoda umożliwia opóźnione wzmocnienie ostrości: asynchronicznie, gdy tylko staje się dostępne.

Pamiętaj, że opóźnione wzmocnienie ostrości działa tylko wtedy, gdy określisz też AudioManager.OnAudioFocusChangeListener w żądaniu audio, ponieważ aplikacja musi oddzwanianie z prośbą o kontakt z klientem.

setOnAudioFocusChangeListener() OnAudioFocusChangeListener jest wymagany tylko wtedy, gdy określisz także willPauseWhenDucked(true) lub setAcceptsDelayedFocusGain(true) w żądaniu.

Istnieją 2 sposoby ustawienia detektora: jedna z użyciem parametru i druga bez z argumentem obsługi. Moduł obsługi to wątek, w którym działa detektor. Jeśli nie określają modułu obsługi, czyli elementu powiązanego z główną funkcją Zajęte miejsce: Looper.

Poniższy przykład pokazuje, jak za pomocą AudioFocusRequest.Builder utworzyć kompilację AudioFocusRequest i żądanie oraz porzucanie ścieżki dźwiękowej:

Kotlin

// initializing variables for audio focus and playback management
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
    setAudioAttributes(AudioAttributes.Builder().run {
        setUsage(AudioAttributes.USAGE_GAME)
        setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        build()
    })
    setAcceptsDelayedFocusGain(true)
    setOnAudioFocusChangeListener(afChangeListener, handler)
    build()
}
val focusLock = Any()

var playbackDelayed = false
var playbackNowAuthorized = false

// requesting audio focus and processing the response
val res = audioManager.requestAudioFocus(focusRequest)
synchronized(focusLock) {
    playbackNowAuthorized = when (res) {
        AudioManager.AUDIOFOCUS_REQUEST_FAILED -> false
        AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
            playbackNow()
            true
        }
        AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> {
            playbackDelayed = true
            false
        }
        else -> false
    }
}

// implementing OnAudioFocusChangeListener to react to focus changes
override fun onAudioFocusChange(focusChange: Int) {
    when (focusChange) {
        AudioManager.AUDIOFOCUS_GAIN ->
            if (playbackDelayed || resumeOnFocusGain) {
                synchronized(focusLock) {
                    playbackDelayed = false
                    resumeOnFocusGain = false
                }
                playbackNow()
            }
        AudioManager.AUDIOFOCUS_LOSS -> {
            synchronized(focusLock) {
                resumeOnFocusGain = false
                playbackDelayed = false
            }
            pausePlayback()
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
            synchronized(focusLock) {
                // only resume if playback is being interrupted
                resumeOnFocusGain = isPlaying()
                playbackDelayed = false
            }
            pausePlayback()
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
            // ... pausing or ducking depends on your app
        }
    }
}

Java

// initializing variables for audio focus and playback management
audioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
playbackAttributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_GAME)
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .build();
focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
        .setAudioAttributes(playbackAttributes)
        .setAcceptsDelayedFocusGain(true)
        .setOnAudioFocusChangeListener(afChangeListener, handler)
        .build();
final Object focusLock = new Object();

boolean playbackDelayed = false;
boolean playbackNowAuthorized = false;

// requesting audio focus and processing the response
int res = audioManager.requestAudioFocus(focusRequest);
synchronized(focusLock) {
    if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
        playbackNowAuthorized = false;
    } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        playbackNowAuthorized = true;
        playbackNow();
    } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
        playbackDelayed = true;
        playbackNowAuthorized = false;
    }
}

// implementing OnAudioFocusChangeListener to react to focus changes
@Override
public void onAudioFocusChange(int focusChange) {
    switch (focusChange) {
        case AudioManager.AUDIOFOCUS_GAIN:
            if (playbackDelayed || resumeOnFocusGain) {
                synchronized(focusLock) {
                    playbackDelayed = false;
                    resumeOnFocusGain = false;
                }
                playbackNow();
            }
            break;
        case AudioManager.AUDIOFOCUS_LOSS:
            synchronized(focusLock) {
                resumeOnFocusGain = false;
                playbackDelayed = false;
            }
            pausePlayback();
            break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            synchronized(focusLock) {
                // only resume if playback is being interrupted
                resumeOnFocusGain = isPlaying();
                playbackDelayed = false;
            }
            pausePlayback();
            break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
            // ... pausing or ducking depends on your app
            break;
        }
    }
}

Automatyczne wyciszanie

W Androidzie 8.0 (poziom interfejsu API 26), gdy inna aplikacja żąda od Ciebie dostępu, koncentruje się ona na AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK system może wyciszyć i przywrócić głośność bez wywoływania wywołania zwrotnego aplikacji onAudioFocusChange().

Automatyczne wyciszanie jest dopuszczalne w przypadku odtwarzania muzyki i filmów aplikacji, nie przydaje się podczas odtwarzania treści głosowych, np. Audiobooki. W takim przypadku aplikacja powinna zostać wstrzymana.

Jeśli chcesz, żeby aplikacja wstrzymywała się na żądanie, a nie wyciszała, a nie wyciszała, utwórz OnAudioFocusChangeListener z metodę wywołania zwrotnego onAudioFocusChange(), która wdraża odpowiednie działanie wstrzymywania/wznawiania. Wywołaj setOnAudioFocusChangeListener(), aby zarejestrować detektora, a następnie nawiąż połączenie setWillPauseWhenDucked(true) , żeby wskazać systemowi, że użyje wywołania zwrotnego, a nie automatycznego wyciszania.

Opóźniony wzmocnienie ostrości

Czasami system nie może spełnić żądania włączenia aktywności audio, ponieważ „zablokowany” przez inną aplikację, na przykład podczas połączenia telefonicznego. W tym przypadku requestAudioFocus() zwraca wartość AUDIOFOCUS_REQUEST_FAILED. W takim przypadku aplikacja nie powinna kontynuować odtwarzania dźwięku, ponieważ nie uzyskała wzmocnienia ostrość.

Metoda setAcceptsDelayedFocusGain(true), która umożliwia aplikacji obsługę żądania zaznaczenia asynchronicznie. Po ustawieniu tej flagi żądanie wysyłane, gdy zaznaczenie jest zablokowane zwraca AUDIOFOCUS_REQUEST_DELAYED. Gdy warunek, który doprowadził do zablokowania dźwięku, już nie ma zaznaczenia, np. po zakończeniu połączenia telefonicznego system zezwala na oczekującą prośbę o koncentrację i wywołuje onAudioFocusChange(), aby powiadomić .

Aby uwzględnić opóźnione wzmocnienie ostrości, musisz utworzyć OnAudioFocusChangeListener z metodą wywołania zwrotnego onAudioFocusChange(), która implementuje oczekiwane działanie i rejestruje detektor, wywołując setOnAudioFocusChangeListener().

Aktywność audio na Androidzie 7.1 i starszych

Gdy dzwonisz requestAudioFocus() musisz określić wskazówkę dotyczącą czasu trwania, która może może zostać uhonorowana przez inną aplikację, która jest obecnie wspierana i gra:

  • Gdy zamierzasz odtworzyć dźwięk, poproś o stały obszar aktywności audio (AUDIOFOCUS_GAIN) w najbliższej przyszłości (np. gdy grasz muzykę) i spodziewasz się, aby zatrzymać odtwarzanie.
  • Gdy spodziewasz się gry, poproś o tymczasowe fokus (AUDIOFOCUS_GAIN_TRANSIENT) będzie słychać dźwięk tylko przez krótki czas i oczekujesz, że poprzedni użytkownik się wstrzyma. gra.
  • Zażądaj chwilowego skupienia dzięki wyciszaniu (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK), aby wskazać, że zamierzasz odtworzyć dźwięk. tylko przez krótki czas i czy poprzedni właściciel może zachować jak się kaczy (zmniejsza) głośność. Oba wyjścia audio są mieszane do strumienia audio. Wyciszanie tła jest szczególnie przydatne w aplikacjach, które korzystają z przerywanego strumienia audio, np. w przypadku dźwiękowych wskazówek dojazdu.

Metoda requestAudioFocus() wymaga też AudioManager.OnAudioFocusChangeListener. Ten detektor powinien być utworzone w ramach tej samej aktywności lub usługi, do której należy Twoja sesja multimediów. it implementuje wywołanie zwrotne onAudioFocusChange(), które aplikacja otrzymuje, gdy inna aplikacja pozyskuje lub porzuca aktywność audio.

Ten fragment wymaga stałego fokusu audio w strumieniu STREAM_MUSIC i rejestruje OnAudioFocusChangeListener do obsługi kolejne zmiany w ostrości. (Detektor zmian jest omówiony w Reagowanie na zmianę ostrości dźwięku).

Kotlin

audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
lateinit var afChangeListener AudioManager.OnAudioFocusChangeListener

...
// Request audio focus for playback
val result: Int = audioManager.requestAudioFocus(
        afChangeListener,
        // Use the music stream.
        AudioManager.STREAM_MUSIC,
        // Request permanent focus.
        AudioManager.AUDIOFOCUS_GAIN
)

if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // Start playback
}

Java

AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
AudioManager.OnAudioFocusChangeListener afChangeListener;

...
// Request audio focus for playback
int result = audioManager.requestAudioFocus(afChangeListener,
                             // Use the music stream.
                             AudioManager.STREAM_MUSIC,
                             // Request permanent focus.
                             AudioManager.AUDIOFOCUS_GAIN);

if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // Start playback
}

Po zakończeniu odtwarzania zadzwoń abandonAudioFocus()

Kotlin

audioManager.abandonAudioFocus(afChangeListener)

Java

// Abandon audio focus when playback complete
audioManager.abandonAudioFocus(afChangeListener);

Jest to powiadomienie dla systemu, że nie musisz już być fokusem, i wyrejestrowanie powiązane konto OnAudioFocusChangeListener. Jeśli Twoje pytanie dotyczy chwilowego skupienia, spowoduje to powiadomienie aplikacji, która wstrzymała lub wstrzymała odtwarzanie, że może ona kontynuować odtwarzanie lub przywrócić jego głośność.

Reagowanie na zmianę ostrości dźwięku

Gdy aplikacja uzyska aktywność audio, musi być w stanie ją opublikować, gdy inna aplikacja żądają skupienia się na dźwięku. W takim przypadku aplikacja odbiera połączenie z onAudioFocusChange() w AudioFocusChangeListener określonego przez Ciebie, gdy aplikacja o nazwie requestAudioFocus().

Parametr focusChange przekazany do onAudioFocusChange() wskazuje rodzaj zachodzących w niej zmian. Odpowiada to do wskazówki dotyczącej czasu trwania wykorzystywanej przez aplikację, na której skupiasz uwagę. Aplikacja powinna odpowiednio zareagować.

Przejściowa utrata ostrości
Jeśli zmiana ostrości jest przejściowa (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK lub AUDIOFOCUS_LOSS_TRANSIENT), aplikacja powinna zostać wycofana (jeśli nie jest taka potrzeba) na automatycznym wyciszaniu wyciszania) lub wstrzymać odtwarzanie, ale w przeciwnym razie zachowają taki sam stan.

Gdy występuje chwilowa utrata ostrości audio, należy kontynuować monitorowanie zmian i przygotuj się do wznowienia normalnego odtwarzania, gdy odzyskasz ostrość. Gdy aplikacja blokująca przestanie się ruszać, otrzymasz oddzwonienie. (AUDIOFOCUS_GAIN). W tym momencie możesz przywrócić normalny poziom głośności. lub uruchom odtwarzanie ponownie.

Trwała utrata ostrości
Jeśli utrata ostrości w dźwięku jest trwała (AUDIOFOCUS_LOSS), inna aplikacja jest odtwarzania dźwięku. Aplikacja powinna od razu wstrzymać odtwarzanie, ponieważ nigdy nie zostanie wstrzymane oddzwonić pod numer AUDIOFOCUS_GAIN. Aby wznowić odtwarzanie, użytkownik musi wykonać wyraźne działanie, np. nacisnąć element sterujący odtwarzaniem transportu. w powiadomieniu lub interfejsie aplikacji.

Fragment kodu poniżej pokazuje, jak zaimplementować OnAudioFocusChangeListener i jego wywołanie zwrotne onAudioFocusChange(). Zwróć uwagę na użycie funkcji Handler do opóźnienia wywołania zwrotnego w przypadku trwałej utraty dźwięku ostrość.

Kotlin

private val handler = Handler()
private val afChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
    when (focusChange) {
        AudioManager.AUDIOFOCUS_LOSS -> {
            // Permanent loss of audio focus
            // Pause playback immediately
            mediaController.transportControls.pause()
            // Wait 30 seconds before stopping playback
            handler.postDelayed(delayedStopRunnable, TimeUnit.SECONDS.toMillis(30))
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
            // Pause playback
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
            // Lower the volume, keep playing
        }
        AudioManager.AUDIOFOCUS_GAIN -> {
            // Your app has been granted audio focus again
            // Raise volume to normal, restart playback if necessary
        }
    }
}

Java

private Handler handler = new Handler();
AudioManager.OnAudioFocusChangeListener afChangeListener =
  new AudioManager.OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
      if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
        // Permanent loss of audio focus
        // Pause playback immediately
        mediaController.getTransportControls().pause();
        // Wait 30 seconds before stopping playback
        handler.postDelayed(delayedStopRunnable,
          TimeUnit.SECONDS.toMillis(30));
      }
      else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
        // Pause playback
      } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
        // Lower the volume, keep playing
      } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
        // Your app has been granted audio focus again
        // Raise volume to normal, restart playback if necessary
      }
    }
  };

Moduł obsługi używa pola Runnable, które wygląda tak:

Kotlin

private var delayedStopRunnable = Runnable {
    mediaController.transportControls.stop()
}

Java

private Runnable delayedStopRunnable = new Runnable() {
    @Override
    public void run() {
        getMediaController().getTransportControls().stop();
    }
};

Aby mieć pewność, że opóźnione zatrzymanie nie rozpocznie się po ponownym uruchomieniu odtwarzania, wywołaj polecenie mHandler.removeCallbacks(mDelayedStopRunnable) w odpowiedzi na dowolny stan zmian. Na przykład zadzwoń do removeCallbacks(), używając numeru onPlay() wywołania zwrotnego, onSkipToNext() itp. Tę metodę należy też wywołać w instrukcji obsługi onDestroy() wywołanie zwrotne podczas czyszczenia zasobów używanych przez usługę.