fix(android): accept denied audio-focus resumes

This commit is contained in:
edde746
2026-07-25 17:38:09 +02:00
parent 96fd47a160
commit 6710c87892
2 changed files with 15 additions and 28 deletions
@@ -720,17 +720,12 @@ class MpvPlayerCore private constructor(
}
}
private fun completeFailedPublicResume(
intent: PublicPauseIntent,
failure: Throwable,
onComplete: ((Result<Unit>) -> Unit)?
) {
rollbackFailedPublicPauseIntent(intent)
private fun completePublicResumeNoOp(onComplete: ((Result<Unit>) -> Unit)?) {
runOnMain {
val completion: Result<Unit> = if (disposing || !isInitialized || !scope.isActive) {
Result.failure(CancellationException("MPV core unavailable"))
} else {
Result.failure(failure)
Result.success(Unit)
}
onComplete?.invoke(completion)
}
@@ -877,12 +872,8 @@ class MpvPlayerCore private constructor(
if (shouldReclaimAudioFocus) {
val focusGranted = audioFocusManager?.requestAudioFocus() == true
if (!focusGranted) {
Log.w(TAG, "Audio focus request denied for public resume")
completeFailedPublicResume(
pauseIntent,
IllegalStateException("Audio focus unavailable for resume"),
onComplete
)
Log.w(TAG, "Audio focus request denied; keeping public resume pending")
completePublicResumeNoOp(onComplete)
return
}
@@ -913,12 +904,8 @@ class MpvPlayerCore private constructor(
}
}
if (interruptedAgain) {
Log.d(TAG, "Public resume interrupted by a newer audio-focus loss")
completeFailedPublicResume(
pauseIntent,
IllegalStateException("Audio focus unavailable for resume"),
onComplete
)
Log.d(TAG, "Public resume deferred by a newer audio-focus loss")
onComplete?.invoke(Result.success(Unit))
} else {
if (deferredForSurface) {
Log.d(TAG, "Deferring public resume until video output is ready")
@@ -949,10 +936,9 @@ class MpvPlayerCore private constructor(
}
}
if (interruptedBeforeWrite) {
Result.failure(IllegalStateException("Audio focus unavailable for resume"))
} else {
Result.success(Unit)
Log.d(TAG, "Public resume write skipped after a newer audio-focus loss")
}
Result.success(Unit)
} catch (error: CancellationException) {
Result.failure(error)
} catch (error: Exception) {
@@ -974,7 +960,7 @@ class MpvPlayerCore private constructor(
synchronized(publicPauseIntentLock) {
publicPauseIntentGeneration == pauseIntent.generation
}
if (isCurrent && completion.isSuccess) {
if (isCurrent && completion.isSuccess && !interruptedBeforeWrite) {
if (paused == true) {
cachedPaused = true
pausedForSurfaceLoss = false
@@ -320,7 +320,7 @@ class MpvPlayerPluginTest {
}
@Test
fun deniedExplicitResumeFocusRequestFailsWithoutWriting() {
fun deniedExplicitResumeFocusRequestCompletesWithoutWriting() {
val writes = ConcurrentLinkedQueue<Pair<String, String>>()
val focusResumeCallbacks = AtomicInteger()
val core = testCore { name, value -> writes += name to value }
@@ -344,12 +344,13 @@ class MpvPlayerPluginTest {
}
awaitCondition { coreOutcome != null }
assertTrue(coreOutcome?.isFailure == true)
assertFalse(coreOutcome?.exceptionOrNull() is CancellationException)
assertTrue(coreOutcome?.isSuccess == true)
assertEquals(1, coreCompletionCount.get())
assertEquals(0, writes.count { it == "pause" to "no" })
assertEquals(true, getBoolean(core, "pausedForAudioFocusLoss"))
assertEquals(true, getBoolean(core, "cachedPaused"))
assertEquals(false, getBoolean(core, "desiredPaused"))
assertEquals(false, getBoolean(core, "resumeBlockedByPublicPause"))
setNextAudioFocusRequestResponse(focusManager, AudioManager.AUDIOFOCUS_REQUEST_FAILED)
val denied = RecordingResult()
@@ -360,7 +361,7 @@ class MpvPlayerPluginTest {
awaitCompletion(denied)
assertEquals(1, denied.completionCount)
assertEquals("SET_PROPERTY_FAILED", denied.errorCode)
assertNull(denied.errorCode)
assertEquals(0, writes.count { it == "pause" to "no" })
assertEquals(true, getBoolean(core, "pausedForAudioFocusLoss"))
@@ -466,7 +467,7 @@ class MpvPlayerPluginTest {
}
assertTrue(blockerOutcome?.isSuccess == true)
assertTrue(resumeOutcome?.isFailure == true)
assertTrue(resumeOutcome?.isSuccess == true)
assertEquals(1, resumeCompletionCount.get())
assertEquals(0, writes.count { it == "pause" to "no" })
assertEquals(true, getBoolean(core, "pausedForAudioFocusLoss"))