Service doesn't get stopped after setting `idle` state with `androidStopForegroundOnPause` disabled
Documented behaviour
AudioServiceConfig.androidStopForegroundOnPause: Whether the Android service should switch to a lower priority state when playback is paused allowing the user to swipe away the notification. Note that while in this lower priority state, the operating system will also be able to kill your service at any time to reclaim resources.
BaseAudioHandler.stop: Stop playback and release resources. The default implementation (which may be overridden) updates playbackState by setting the processing state to AudioProcessingState.idle which disables the system notification.
Actual behaviour
Changing androidStopForegroundOnPause from true (default) to false no longer allows stopping foreground service (and notification) by setting AudioProcessingState.idle:
playbackState.add(
PlaybackState(
playing: false,
processingState: AudioProcessingState.idle,
)
);
Minimal reproduction project
Official example: main.dart
Reproduction steps
Proper behavior:
- Press "play".
- Press "stop".
- Notification gets destroyed, and Android task manager no longer shows app in its "task manager".
Wrong behavior.
- Change
androidStopForegroundOnPauseto false. - Press "play".
- Press "stop".
- Notification does not get dismissed, and Android "task manager" shows that app is still running.
Output of flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.22.2, on Microsoft Windows [Version 10.0.22631.3958], locale ru-RU)
[✓] Windows Version (Installed version of Windows is version 10 or higher)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✗] Chrome - develop for the web (Cannot find Chrome executable at .\Google\Chrome\Application\chrome.exe)
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✓] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.8.3)
[✓] Android Studio (version 2022.3)
[✓] VS Code (version 1.91.1)
[✓] Connected device (3 available)
[✓] Network resources
Devices exhibiting the bug
Google Pixel 8, Android 14 (AP2A.240705.005)
Context
I'm forced to use androidStopForegroundOnPause = false because my app can pause playback due to interruptions. After setting androidStopForegroundOnPause = true, my app can pause playback, but it gets ForegroundServiceStartNotAllowedException exception.
Changing
androidStopForegroundOnPausefrom true (default) to false no longer allows stopping foreground service (and notification) by settingAudioProcessingState.idle:
That's the correct behaviour. If you want to instruct Android to call stopForeground on pause, you have to set this to true (the default).
Yeah, that makes sense, but the problem I'm facing - no way to get rid of that notification by setting the state to idle. There is no method like "destroyNotification", and this is a problem for me.
So, I want to clarify a bit: I'm not asking "why doesn't service stop when player is paused", but rather "why doesn't service stop when player is in idle state".
After digging a bit, I found this issue: #996. This comment explains the exact same issue I have. I'm strongly against ignoring battery optimizations, so I can't use this here.
I'm facing a similar issue @Zensonaton. I feel like as things currently stand, there are two options:
- Keep
androidStopForegroundOnPause = trueand risk the service being killed in the background (this seems to happen when receiving notifications or calls during playback - possibly the switch to the lower priority state makes it a good candidate to be killed by the OS) - Set
androidStopForegroundOnPause = falsewhich seems to keep the service alive correctly but has the downside of the audio notification lingering after playback has finished. It does (obviously) get dismissed when you swipe the app away, but not ideal. I know exactly where in the app logic I'd want to dismiss the notification (i.e. when navigating away from my in-app audio player UI).
I also agree that the battery optimization option isn't great, but I also understand that we're kinda fighting against flaws in the OS at this point.
Is it possible to integrate a "destroyNotification" function to manually dismiss the notification?
I'm using the default AudioServiceConfig but still the notification behavior is inconsistent after stopping the audio and calling the stop method of BaseAudioHandler. let's say 5 out of 10 times the notification gets dismissed while the rest of times it stays there.
AudioServiceConfig(
androidNotificationChannelId: 'test Notifications',
androidNotificationChannelName: 'test Notifications',
androidShowNotificationBadge: false)
I made a few modifications that I think better aligns with the current AudioProcessingState: https://github.com/Colton127/audio_service
AudioProcessingState.idle: Stop foreground service and remove notification.
AudioProcessingState.completed: Stop foreground service, but keep notification active, allowing users to restart playback at a later time through the notification.
On my branch, AudioProcessingState.idle always kills the notification on Android 14, but I don't think it's possible on Android 11.
I believe the lifecycle of the service should mirror that of Spotify and YouTube: The service remains active until the notification or app is swiped away by the user. Previously, this wasn't necessary, but now that we cannot momentarily pause and resume the service in the background, we need to keep it alive.
@Colton127 version is great, but their implementation was a bit weird for me for some reason.
You can look at my commit 5636135 in my own fork. It's working flawlessly: foreground notification exists when player is working, my app doesn't get killed by the system (and I see that app is listed in "running apps"), app still considered running even after pausing playback, and notification disappears when player is stopped.
In my opinion, those changes should be made in main repo.
I have the same problem (v. 0.18.18). I have to set androidStopForegroundOnPause to false, otherwise, the app gets killed by the system when playing audio in the background. However, doing that keeps the app in a wake lock and drains the battery, even when the audio is paused in the background. Calling BaseAudioHandler.stop() does not help.