finish recording gracefully when audio focus is lost
if something else grabs focus mid-recording (phone call, etc), stop the recording and keep the partial result in preview state instead of silently recording garbage Signed-off-by: vmfunc <celeste@linux.com>
This commit is contained in:
parent
7bd157f032
commit
bddc5a63f4
2 changed files with 30 additions and 1 deletions
|
|
@ -249,7 +249,11 @@ class DefaultVoiceMessageComposerPresenter(
|
||||||
|
|
||||||
private fun CoroutineScope.startRecording() = launch {
|
private fun CoroutineScope.startRecording() = launch {
|
||||||
try {
|
try {
|
||||||
audioFocus.requestAudioFocus(AudioFocusRequester.RecordVoiceMessage) {}
|
audioFocus.requestAudioFocus(AudioFocusRequester.RecordVoiceMessage) {
|
||||||
|
// something else grabbed focus (phone call, etc) - finish gracefully
|
||||||
|
// so the user keeps their partial recording
|
||||||
|
sessionCoroutineScope.finishRecording()
|
||||||
|
}
|
||||||
voiceRecorder.startRecord()
|
voiceRecorder.startRecord()
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
audioFocus.releaseAudioFocus()
|
audioFocus.releaseAudioFocus()
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,30 @@ class DefaultVoiceMessageComposerPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - audio focus loss during recording finishes gracefully`() = runTest {
|
||||||
|
var onFocusLost: (() -> Unit)? = null
|
||||||
|
val testAudioFocus = FakeAudioFocus(
|
||||||
|
requestAudioFocusResult = { _, callback -> onFocusLost = callback },
|
||||||
|
releaseAudioFocusResult = { },
|
||||||
|
)
|
||||||
|
val presenter = createDefaultVoiceMessageComposerPresenter(audioFocus = testAudioFocus)
|
||||||
|
presenter.test {
|
||||||
|
awaitItem().eventSink(VoiceMessageComposerEvent.RecorderEvent(VoiceMessageRecorderEvent.Start))
|
||||||
|
awaitItem()
|
||||||
|
|
||||||
|
// simulate focus loss (phone call, etc)
|
||||||
|
onFocusLost?.invoke()
|
||||||
|
advanceUntilIdle()
|
||||||
|
|
||||||
|
val finalState = awaitItem()
|
||||||
|
assertThat(finalState.voiceMessageState).isEqualTo(aPreviewState())
|
||||||
|
voiceRecorder.assertCalls(started = 1, stopped = 1)
|
||||||
|
|
||||||
|
cancelAndIgnoreRemainingEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - abort recording`() = runTest {
|
fun `present - abort recording`() = runTest {
|
||||||
val presenter = createDefaultVoiceMessageComposerPresenter()
|
val presenter = createDefaultVoiceMessageComposerPresenter()
|
||||||
|
|
@ -687,6 +711,7 @@ class DefaultVoiceMessageComposerPresenterTest {
|
||||||
private fun TestScope.createDefaultVoiceMessageComposerPresenter(
|
private fun TestScope.createDefaultVoiceMessageComposerPresenter(
|
||||||
permissionsPresenter: PermissionsPresenter = createFakePermissionsPresenter(),
|
permissionsPresenter: PermissionsPresenter = createFakePermissionsPresenter(),
|
||||||
voiceRecorder: VoiceRecorder = this@DefaultVoiceMessageComposerPresenterTest.voiceRecorder,
|
voiceRecorder: VoiceRecorder = this@DefaultVoiceMessageComposerPresenterTest.voiceRecorder,
|
||||||
|
audioFocus: AudioFocus = this@DefaultVoiceMessageComposerPresenterTest.audioFocus,
|
||||||
): DefaultVoiceMessageComposerPresenter {
|
): DefaultVoiceMessageComposerPresenter {
|
||||||
return DefaultVoiceMessageComposerPresenter(
|
return DefaultVoiceMessageComposerPresenter(
|
||||||
sessionCoroutineScope = backgroundScope,
|
sessionCoroutineScope = backgroundScope,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue