Reimplement voice note proximity locking.

Proximity lock was tied to the VoiceNotePlaybackService instead of to the Activity, and it made for some strange code decisions. This rewrite now ties locking to the activity, where it should have been in the first place, and hopefully solves a few proximity / playback bugs on the way. In addition, it conforms to SRP better as it will send a command to the player to change the audio attributes as necessary instead of directly operating on a player instance.
This commit is contained in:
Alex Hart
2021-08-03 10:03:33 -03:00
parent 2d5492ffac
commit c78e283084
6 changed files with 290 additions and 153 deletions

View File

@@ -0,0 +1,105 @@
package org.thoughtcrime.securesms.components.voice
import android.app.Application
import android.media.AudioManager
import android.os.Bundle
import android.support.v4.media.session.MediaSessionCompat
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.audio.AudioAttributes
import org.junit.Assert.assertArrayEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE, application = Application::class)
class VoiceNotePlaybackControllerTest {
private val mediaSessionCompat = mock(MediaSessionCompat::class.java)
private val playbackParameters = VoiceNotePlaybackParameters(mediaSessionCompat)
private val testSubject = VoiceNotePlaybackController(playbackParameters)
private val mediaAudioAttributes = AudioAttributes.Builder().setContentType(C.CONTENT_TYPE_MUSIC).setUsage(C.USAGE_MEDIA).build()
private val callAudioAttributes = AudioAttributes.Builder().setContentType(C.CONTENT_TYPE_SPEECH).setUsage(C.USAGE_VOICE_COMMUNICATION).build()
private val player: SimpleExoPlayer = mock(SimpleExoPlayer::class.java)
@Test
fun `When I getCommands, then I expect PLAYBACK_SPEED and AUDIO_STREAM`() {
assertArrayEquals(arrayOf(VoiceNotePlaybackService.ACTION_NEXT_PLAYBACK_SPEED, VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM), testSubject.commands)
}
@Test
fun `Given stream is media, When I onCommand for voice, then I expect the stream to switch to voice and continue playback`() {
// GIVEN
`when`(player.audioAttributes).thenReturn(mediaAudioAttributes)
val command = VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM
val extras = Bundle().apply { putInt(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, AudioManager.STREAM_VOICE_CALL) }
val expected = callAudioAttributes
// WHEN
testSubject.onCommand(player, command, extras, null)
// THEN
verify(player).playWhenReady = false
verify(player).audioAttributes = expected
verify(player).playWhenReady = true
}
@Test
fun `Given stream is voice, When I onCommand for media, then I expect the stream to switch to media and pause playback`() {
// GIVEN
`when`(player.audioAttributes).thenReturn(callAudioAttributes)
val command = VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM
val extras = Bundle().apply { putInt(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, AudioManager.STREAM_MUSIC) }
val expected = mediaAudioAttributes
// WHEN
testSubject.onCommand(player, command, extras, null)
// THEN
verify(player).playWhenReady = false
verify(player).audioAttributes = expected
verify(player, Mockito.never()).playWhenReady = true
}
@Test
fun `Given stream is voice, When I onCommand for voice, then I expect no change`() {
// GIVEN
`when`(player.audioAttributes).thenReturn(callAudioAttributes)
val command = VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM
val extras = Bundle().apply { putInt(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, AudioManager.STREAM_VOICE_CALL) }
// WHEN
testSubject.onCommand(player, command, extras, null)
// THEN
verify(player, Mockito.never()).playWhenReady = anyBoolean()
verify(player, Mockito.never()).audioAttributes = any()
}
@Test
fun `Given stream is media, When I onCommand for media, then I expect no change`() {
// GIVEN
`when`(player.audioAttributes).thenReturn(mediaAudioAttributes)
val command = VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM
val extras = Bundle().apply { putInt(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, AudioManager.STREAM_MUSIC) }
// WHEN
testSubject.onCommand(player, command, extras, null)
// THEN
verify(player, Mockito.never()).playWhenReady = anyBoolean()
verify(player, Mockito.never()).audioAttributes = any()
}
}