From 5f8e3ce8511c1aa1883098f2610abaedc0e6901f Mon Sep 17 00:00:00 2001 From: tzugen Date: Thu, 22 Apr 2021 10:25:17 +0200 Subject: [PATCH] Modernize AudioFocusHandler --- .../ultrasonic/service/AudioFocusHandler.kt | 127 +++++++++++++----- 1 file changed, 94 insertions(+), 33 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt index c3641729..4d5511e5 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt @@ -1,8 +1,14 @@ package org.moire.ultrasonic.service import android.content.Context +import android.media.AudioAttributes import android.media.AudioManager import android.media.AudioManager.OnAudioFocusChangeListener +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.media.AudioAttributesCompat +import androidx.media.AudioFocusRequestCompat +import androidx.media.AudioManagerCompat import org.koin.java.KoinJavaComponent.inject import org.moire.ultrasonic.domain.PlayerState import org.moire.ultrasonic.util.Constants @@ -11,54 +17,109 @@ import timber.log.Timber class AudioFocusHandler(private val context: Context) { // TODO: This is a circular reference, try to remove it + // This should be doable by using the native MediaController framework private val mediaPlayerControllerLazy = inject(MediaPlayerController::class.java) + private val audioManager by lazy { + context.getSystemService(Context.AUDIO_SERVICE) as AudioManager + } + + private val preferences by lazy { + Util.getPreferences(context) + } + + private val lossPref: Int + get() = preferences.getString(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")!!.toInt() + + private val audioAttributesCompat by lazy { + AudioAttributesCompat.Builder() + .setUsage(AudioAttributesCompat.USAGE_MEDIA) + .setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC) + .setLegacyStreamType(AudioManager.STREAM_MUSIC) + .build() + } + fun requestAudioFocus() { if (!hasFocus) { - val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager hasFocus = true + AudioManagerCompat.requestAudioFocus(audioManager, focusRequest) + } + } + private val listener = OnAudioFocusChangeListener { focusChange -> - audioManager.requestAudioFocus(object : OnAudioFocusChangeListener { - override fun onAudioFocusChange(focusChange: Int) { - val mediaPlayerController = mediaPlayerControllerLazy.value - if ((focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) && !mediaPlayerController.isJukeboxEnabled) { - Timber.v("Lost Audio Focus") - if (mediaPlayerController.playerState === PlayerState.STARTED) { - val preferences = Util.getPreferences(context) - val lossPref = preferences.getString(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")!!.toInt() - if (lossPref == 2 || lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { - lowerFocus = true - mediaPlayerController.setVolume(0.1f) - } else if (lossPref == 0 || lossPref == 1) { - pauseFocus = true - mediaPlayerController.pause() - } + val mediaPlayerController = mediaPlayerControllerLazy.value + + when (focusChange) { + AudioManager.AUDIOFOCUS_GAIN -> { + Timber.v("Regained Audio Focus") + if (pauseFocus) { + pauseFocus = false + mediaPlayerController.start() + } else if (lowerFocus) { + lowerFocus = false + mediaPlayerController.setVolume(1.0f) + } + } + AudioManager.AUDIOFOCUS_LOSS -> { + if (!mediaPlayerController.isJukeboxEnabled) { + hasFocus = false + mediaPlayerController.pause() + AudioManagerCompat.abandonAudioFocusRequest(audioManager, focusRequest) + Timber.v("Abandoned Audio Focus") + } + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { + if (!mediaPlayerController.isJukeboxEnabled) { + Timber.v("Lost Audio Focus") + + if (mediaPlayerController.playerState === PlayerState.STARTED) { + if (lossPref == 0 || lossPref == 1) { + pauseFocus = true + mediaPlayerController.pause() } - } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { - Timber.v("Regained Audio Focus") - if (pauseFocus) { - pauseFocus = false - mediaPlayerController.start() - } else if (lowerFocus) { - lowerFocus = false - mediaPlayerController.setVolume(1.0f) - } - } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS && !mediaPlayerController.isJukeboxEnabled) { - hasFocus = false - mediaPlayerController.pause() - audioManager.abandonAudioFocus(this) - Timber.v("Abandoned Audio Focus") } } - }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN) - Timber.v("Got Audio Focus") + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { + if (!mediaPlayerController.isJukeboxEnabled) { + Timber.v("Lost Audio Focus") + + if (mediaPlayerController.playerState === PlayerState.STARTED) { + if (lossPref == 2 || lossPref == 1) { + lowerFocus = true + mediaPlayerController.setVolume(0.1f) + } else if (lossPref == 0 || lossPref == 1) { + pauseFocus = true + mediaPlayerController.pause() + } + } + } + } } } + private val focusRequest: AudioFocusRequestCompat by lazy { + AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN) + .setAudioAttributes(audioAttributesCompat) + .setWillPauseWhenDucked(true) + .setOnAudioFocusChangeListener(listener) + .build() + } + companion object { private var hasFocus = false private var pauseFocus = false private var lowerFocus = false + + // TODO: This can be removed if we switch to androidx.media2.player + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + fun getAudioAttributes(): AudioAttributes { + return AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .setLegacyStreamType(AudioManager.STREAM_MUSIC) + .build() + } } -} \ No newline at end of file +}