mirror of
https://github.com/nextcloud/talk-android
synced 2025-03-06 06:15:12 +00:00
Merge pull request #3535 from nextcloud/handle-audio-focus
Handle audio focus and becoming noisy
This commit is contained in:
commit
ffdb93204d
@ -31,10 +31,12 @@ package com.nextcloud.talk.chat
|
||||
import android.Manifest
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.AssetFileDescriptor
|
||||
import android.content.res.Resources
|
||||
@ -42,7 +44,9 @@ import android.database.Cursor
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.AudioFocusRequest
|
||||
import android.media.AudioFormat
|
||||
import android.media.AudioManager
|
||||
import android.media.AudioRecord
|
||||
import android.media.MediaPlayer
|
||||
import android.media.MediaRecorder
|
||||
@ -384,6 +388,20 @@ class ChatActivity :
|
||||
private var lastRecordMediaPosition: Int = 0
|
||||
private var lastRecordedSeeked: Boolean = false
|
||||
|
||||
private val audioFocusChangeListener = getAudioFocusChangeListener()
|
||||
|
||||
private val noisyAudioStreamReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
chatViewModel.isPausedDueToBecomingNoisy = true
|
||||
if (isVoicePreviewPlaying) {
|
||||
pausePreviewVoicePlaying()
|
||||
}
|
||||
if (currentlyPlayedVoiceMessage != null) {
|
||||
pausePlayback(currentlyPlayedVoiceMessage!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var participantPermissions: ParticipantPermissions
|
||||
|
||||
private var videoURI: Uri? = null
|
||||
@ -1099,7 +1117,9 @@ class ChatActivity :
|
||||
|
||||
binding.messageInputView.micInputCloud.setOnClickListener {
|
||||
if (mediaRecorderState == MediaRecorderState.RECORDING) {
|
||||
recorder?.stop()
|
||||
audioFocusRequest(false) {
|
||||
recorder?.stop()
|
||||
}
|
||||
mediaRecorderState = MediaRecorderState.INITIAL
|
||||
stopMicInputRecordingAnimation()
|
||||
showPreviewVoiceRecording(true)
|
||||
@ -1328,8 +1348,11 @@ class ChatActivity :
|
||||
duration = it.duration.toLong()
|
||||
interpolator = LinearInterpolator()
|
||||
}
|
||||
voicePreviewMediaPlayer!!.start()
|
||||
voicePreviewObjectAnimator!!.start()
|
||||
audioFocusRequest(true) {
|
||||
voicePreviewMediaPlayer!!.start()
|
||||
voicePreviewObjectAnimator!!.start()
|
||||
handleBecomingNoisyBroadcast(register = true)
|
||||
}
|
||||
}
|
||||
|
||||
setOnCompletionListener {
|
||||
@ -1343,15 +1366,21 @@ class ChatActivity :
|
||||
if (voicePreviewMediaPlayer == null) {
|
||||
initPreviewVoiceRecording()
|
||||
} else {
|
||||
voicePreviewMediaPlayer!!.start()
|
||||
voicePreviewObjectAnimator!!.resume()
|
||||
audioFocusRequest(true) {
|
||||
voicePreviewMediaPlayer!!.start()
|
||||
voicePreviewObjectAnimator!!.resume()
|
||||
handleBecomingNoisyBroadcast(register = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun pausePreviewVoicePlaying() {
|
||||
Log.d(TAG, "paused preview voice recording")
|
||||
voicePreviewMediaPlayer!!.pause()
|
||||
voicePreviewObjectAnimator!!.pause()
|
||||
audioFocusRequest(false) {
|
||||
voicePreviewMediaPlayer!!.pause()
|
||||
voicePreviewObjectAnimator!!.pause()
|
||||
handleBecomingNoisyBroadcast(register = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopPreviewVoicePlaying() {
|
||||
@ -1361,9 +1390,12 @@ class ChatActivity :
|
||||
voicePreviewObjectAnimator!!.end()
|
||||
voicePreviewObjectAnimator = null
|
||||
binding.messageInputView.seekBar.clearAnimation()
|
||||
voicePreviewMediaPlayer!!.stop()
|
||||
voicePreviewMediaPlayer!!.release()
|
||||
voicePreviewMediaPlayer = null
|
||||
audioFocusRequest(false) {
|
||||
voicePreviewMediaPlayer!!.stop()
|
||||
voicePreviewMediaPlayer!!.release()
|
||||
voicePreviewMediaPlayer = null
|
||||
handleBecomingNoisyBroadcast(register = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1817,6 +1849,73 @@ class ChatActivity :
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAudioFocusChangeListener(): AudioManager.OnAudioFocusChangeListener {
|
||||
return AudioManager.OnAudioFocusChangeListener { flag ->
|
||||
when (flag) {
|
||||
AudioManager.AUDIOFOCUS_LOSS -> {
|
||||
chatViewModel.isPausedDueToBecomingNoisy = false
|
||||
if (isVoicePreviewPlaying) {
|
||||
stopPreviewVoicePlaying()
|
||||
}
|
||||
if (currentlyPlayedVoiceMessage != null) {
|
||||
stopMediaPlayer(currentlyPlayedVoiceMessage!!)
|
||||
}
|
||||
}
|
||||
|
||||
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
|
||||
chatViewModel.isPausedDueToBecomingNoisy = false
|
||||
if (isVoicePreviewPlaying) {
|
||||
pausePreviewVoicePlaying()
|
||||
}
|
||||
if (currentlyPlayedVoiceMessage != null) {
|
||||
pausePlayback(currentlyPlayedVoiceMessage!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun audioFocusRequest(shouldRequestFocus: Boolean, onGranted: () -> Unit) {
|
||||
if (chatViewModel.isPausedDueToBecomingNoisy) {
|
||||
onGranted()
|
||||
return
|
||||
}
|
||||
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
val duration = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
|
||||
|
||||
val isGranted: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val focusRequest = AudioFocusRequest.Builder(duration)
|
||||
.setOnAudioFocusChangeListener(audioFocusChangeListener)
|
||||
.build()
|
||||
if (shouldRequestFocus) {
|
||||
audioManager.requestAudioFocus(focusRequest)
|
||||
} else {
|
||||
audioManager.abandonAudioFocusRequest(focusRequest)
|
||||
}
|
||||
} else {
|
||||
@Deprecated("This method was deprecated in API level 26.")
|
||||
if (shouldRequestFocus) {
|
||||
audioManager.requestAudioFocus(audioFocusChangeListener, AudioManager.STREAM_MUSIC, duration)
|
||||
} else {
|
||||
audioManager.abandonAudioFocus(audioFocusChangeListener)
|
||||
}
|
||||
}
|
||||
if (isGranted == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
onGranted()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBecomingNoisyBroadcast(register: Boolean) {
|
||||
if (register && !chatViewModel.receiverRegistered) {
|
||||
registerReceiver(noisyAudioStreamReceiver, IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY))
|
||||
chatViewModel.receiverRegistered = true
|
||||
} else if (!chatViewModel.receiverUnregistered) {
|
||||
unregisterReceiver(noisyAudioStreamReceiver)
|
||||
chatViewModel.receiverUnregistered = true
|
||||
chatViewModel.receiverRegistered = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun startPlayback(message: ChatMessage) {
|
||||
if (!active) {
|
||||
// don't begin to play voice message if screen is not visible anymore.
|
||||
@ -1830,8 +1929,10 @@ class ChatActivity :
|
||||
|
||||
mediaPlayer?.let {
|
||||
if (!it.isPlaying) {
|
||||
it.start()
|
||||
Log.d(TAG, "MediaPlayer has Started")
|
||||
audioFocusRequest(true) {
|
||||
it.start()
|
||||
handleBecomingNoisyBroadcast(register = true)
|
||||
}
|
||||
}
|
||||
|
||||
mediaPlayerHandler = Handler()
|
||||
@ -1866,8 +1967,10 @@ class ChatActivity :
|
||||
|
||||
private fun pausePlayback(message: ChatMessage) {
|
||||
if (mediaPlayer!!.isPlaying) {
|
||||
mediaPlayer!!.pause()
|
||||
Log.d(TAG, "MediaPlayer is paused")
|
||||
audioFocusRequest(false) {
|
||||
mediaPlayer!!.pause()
|
||||
handleBecomingNoisyBroadcast(register = false)
|
||||
}
|
||||
}
|
||||
|
||||
message.isPlayingVoiceMessage = false
|
||||
@ -1925,7 +2028,10 @@ class ChatActivity :
|
||||
mediaPlayer?.let {
|
||||
if (it.isPlaying) {
|
||||
Log.d(TAG, "media player is stopped")
|
||||
it.stop()
|
||||
audioFocusRequest(false) {
|
||||
it.stop()
|
||||
handleBecomingNoisyBroadcast(register = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: IllegalStateException) {
|
||||
@ -2141,8 +2247,10 @@ class ChatActivity :
|
||||
private fun stopMicInputRecordingAnimation() {
|
||||
if (micInputAudioRecordThread != null) {
|
||||
Log.d(TAG, "Mic Animation Ended")
|
||||
micInputAudioRecorder.stop()
|
||||
micInputAudioRecorder.release()
|
||||
audioFocusRequest(false) {
|
||||
micInputAudioRecorder.stop()
|
||||
micInputAudioRecorder.release()
|
||||
}
|
||||
isMicInputAudioThreadRunning = false
|
||||
micInputAudioRecordThread = null
|
||||
}
|
||||
@ -2193,7 +2301,9 @@ class ChatActivity :
|
||||
}
|
||||
|
||||
try {
|
||||
start()
|
||||
audioFocusRequest(true) {
|
||||
start()
|
||||
}
|
||||
mediaRecorderState = MediaRecorderState.RECORDING
|
||||
Log.d(TAG, "recording started")
|
||||
} catch (e: IllegalStateException) {
|
||||
@ -2234,8 +2344,10 @@ class ChatActivity :
|
||||
recorder?.apply {
|
||||
try {
|
||||
if (mediaRecorderState == MediaRecorderState.RECORDING) {
|
||||
stop()
|
||||
reset()
|
||||
audioFocusRequest(false) {
|
||||
stop()
|
||||
reset()
|
||||
}
|
||||
mediaRecorderState = MediaRecorderState.INITIAL
|
||||
Log.d(TAG, "stopped recorder")
|
||||
}
|
||||
|
@ -48,6 +48,11 @@ class ChatViewModel @Inject constructor(private val repository: ChatRepository)
|
||||
open class GetReminderExistState(val reminder: Reminder) : ViewState
|
||||
|
||||
private val _getReminderExistState: MutableLiveData<ViewState> = MutableLiveData(GetReminderStartState)
|
||||
|
||||
var isPausedDueToBecomingNoisy = false
|
||||
var receiverRegistered = false
|
||||
var receiverUnregistered = false
|
||||
|
||||
val getReminderExistState: LiveData<ViewState>
|
||||
get() = _getReminderExistState
|
||||
|
||||
|
@ -44,6 +44,7 @@ import androidx.core.view.marginBottom
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.media3.common.AudioAttributes
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
@ -165,7 +166,10 @@ class FullScreenMediaActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun initializePlayer() {
|
||||
player = ExoPlayer.Builder(applicationContext).build()
|
||||
player = ExoPlayer.Builder(applicationContext)
|
||||
.setAudioAttributes(AudioAttributes.DEFAULT, true)
|
||||
.setHandleAudioBecomingNoisy(true)
|
||||
.build()
|
||||
binding.playerView.player = player
|
||||
}
|
||||
|
||||
@ -202,6 +206,7 @@ class FullScreenMediaActivity : AppCompatActivity() {
|
||||
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
|
||||
supportActionBar?.show()
|
||||
}
|
||||
|
||||
private fun applyWindowInsets() {
|
||||
val playerView = binding.playerView
|
||||
val exoControls = playerView.findViewById<FrameLayout>(R.id.exo_bottom_bar)
|
||||
|
Loading…
Reference in New Issue
Block a user