playback: fix headset focus autoplay issue
Fix an issue where headset focus would result in unexpected playback whenever the service started. AudioManager.ACTION_HEADSET_PLUG seems to always fire when the initial BroadcastReceiver is set up, which results in a weird bug where if a wired headset is connected while PlaybackService is started, playback will start immediately, which was not user friendly. I fear that this may result in an edge case that results in headset focus not firing in an unrelated situation, which in that case I would be forced to remove headset autoplay entirely (or at least relegate it to a quirk option).
This commit is contained in:
parent
1e39ceb9fc
commit
6d003c308b
8 changed files with 20 additions and 8 deletions
|
@ -15,6 +15,7 @@ from the system theme was used [#80]
|
||||||
- Fixed music loading failure that would occur when certain paths were parsed [#84]
|
- Fixed music loading failure that would occur when certain paths were parsed [#84]
|
||||||
- Fixed incorrect track numbers when the tag was formatted as NN/TT [#88]
|
- Fixed incorrect track numbers when the tag was formatted as NN/TT [#88]
|
||||||
- Fixed years deliberately set as "0" showing up as "No Date"
|
- Fixed years deliberately set as "0" showing up as "No Date"
|
||||||
|
- Fixed headset management unexpectedly starting audio when the app initially opens
|
||||||
|
|
||||||
#### What's Changed
|
#### What's Changed
|
||||||
- All cover art is now cropped to a 1:1 aspect ratio
|
- All cover art is now cropped to a 1:1 aspect ratio
|
||||||
|
|
|
@ -29,6 +29,10 @@ import org.oxycblt.auxio.coil.GenreImageFetcher
|
||||||
import org.oxycblt.auxio.coil.MusicKeyer
|
import org.oxycblt.auxio.coil.MusicKeyer
|
||||||
import org.oxycblt.auxio.settings.SettingsManager
|
import org.oxycblt.auxio.settings.SettingsManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Phase out databinding
|
||||||
|
* TODO: Rework sealed classes to minimize whens and maximize overrides
|
||||||
|
*/
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
class AuxioApp : Application(), ImageLoaderFactory {
|
class AuxioApp : Application(), ImageLoaderFactory {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
|
|
@ -43,7 +43,6 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
|
||||||
* TODO: Add a new view for crashes with a stack trace
|
* TODO: Add a new view for crashes with a stack trace
|
||||||
* TODO: Custom language support
|
* TODO: Custom language support
|
||||||
* TODO: Rework menus [perhaps add multi-select]
|
* TODO: Rework menus [perhaps add multi-select]
|
||||||
* TODO: Phase out databinding
|
|
||||||
*/
|
*/
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
private val playbackModel: PlaybackViewModel by viewModels()
|
private val playbackModel: PlaybackViewModel by viewModels()
|
||||||
|
|
|
@ -56,6 +56,7 @@ import org.oxycblt.auxio.util.logTraceOrThrow
|
||||||
* views for each respective item.
|
* views for each respective item.
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
* TODO: Make tabs invisible when there is only one
|
* TODO: Make tabs invisible when there is only one
|
||||||
|
* TODO: Add duration and song count sorts
|
||||||
*/
|
*/
|
||||||
class HomeFragment : Fragment() {
|
class HomeFragment : Fragment() {
|
||||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
|
|
|
@ -149,7 +149,7 @@ data class Song(
|
||||||
*/
|
*/
|
||||||
data class Album(
|
data class Album(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
/** The latest year of the songs in this album. */
|
/** The latest year of the songs in this album. Null if none of the songs had metadata. */
|
||||||
val year: Int?,
|
val year: Int?,
|
||||||
/** The URI for the cover art corresponding to this album. */
|
/** The URI for the cover art corresponding to this album. */
|
||||||
val albumCoverUri: Uri,
|
val albumCoverUri: Uri,
|
||||||
|
|
|
@ -241,6 +241,7 @@ class MusicLoader {
|
||||||
// Use the song with the latest year as our metadata song.
|
// Use the song with the latest year as our metadata song.
|
||||||
// This allows us to replicate the LAST_YEAR field, which is useful as it means that
|
// This allows us to replicate the LAST_YEAR field, which is useful as it means that
|
||||||
// weird years like "0" wont show up if there are alternatives.
|
// weird years like "0" wont show up if there are alternatives.
|
||||||
|
// TODO: Weigh songs with null years lower than songs with zero years
|
||||||
val templateSong = requireNotNull(
|
val templateSong = requireNotNull(
|
||||||
albumSongs.maxByOrNull { it.internalMediaStoreYear ?: 0 }
|
albumSongs.maxByOrNull { it.internalMediaStoreYear ?: 0 }
|
||||||
)
|
)
|
||||||
|
|
|
@ -69,7 +69,8 @@ class MusicStore private constructor() {
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
|
|
||||||
val loader = MusicLoader()
|
val loader = MusicLoader()
|
||||||
val library = loader.load(context) ?: return Response.Err(ErrorKind.NO_MUSIC)
|
val library = loader.load(context)
|
||||||
|
?: return Response.Err(ErrorKind.NO_MUSIC)
|
||||||
|
|
||||||
mSongs = library.songs
|
mSongs = library.songs
|
||||||
mAlbums = library.albums
|
mAlbums = library.albums
|
||||||
|
@ -78,7 +79,7 @@ class MusicStore private constructor() {
|
||||||
|
|
||||||
logD("Music load completed successfully in ${System.currentTimeMillis() - start}ms")
|
logD("Music load completed successfully in ${System.currentTimeMillis() - start}ms")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logE("Something went horribly wrong")
|
logE("Music loading failed.")
|
||||||
logE(e.stackTraceToString())
|
logE(e.stackTraceToString())
|
||||||
return Response.Err(ErrorKind.FAILED)
|
return Response.Err(ErrorKind.FAILED)
|
||||||
}
|
}
|
||||||
|
|
|
@ -439,7 +439,6 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
|
||||||
private fun stopForegroundAndNotification() {
|
private fun stopForegroundAndNotification() {
|
||||||
stopForeground(true)
|
stopForeground(true)
|
||||||
notificationManager.cancel(PlaybackNotification.NOTIFICATION_ID)
|
notificationManager.cancel(PlaybackNotification.NOTIFICATION_ID)
|
||||||
|
|
||||||
isForeground = false
|
isForeground = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,6 +447,8 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
|
||||||
* TODO: Don't fire when the service initially starts?
|
* TODO: Don't fire when the service initially starts?
|
||||||
*/
|
*/
|
||||||
private inner class PlaybackReceiver : BroadcastReceiver() {
|
private inner class PlaybackReceiver : BroadcastReceiver() {
|
||||||
|
private var handledInitialHeadsetPlug = false
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
// --- SYSTEM EVENTS ---
|
// --- SYSTEM EVENTS ---
|
||||||
|
@ -461,12 +462,16 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
|
||||||
AudioManager.ACTION_AUDIO_BECOMING_NOISY -> pauseFromPlug()
|
AudioManager.ACTION_AUDIO_BECOMING_NOISY -> pauseFromPlug()
|
||||||
|
|
||||||
AudioManager.ACTION_HEADSET_PLUG -> {
|
AudioManager.ACTION_HEADSET_PLUG -> {
|
||||||
|
if (handledInitialHeadsetPlug) {
|
||||||
when (intent.getIntExtra("state", -1)) {
|
when (intent.getIntExtra("state", -1)) {
|
||||||
0 -> pauseFromPlug()
|
0 -> pauseFromPlug()
|
||||||
1 -> resumeFromPlug()
|
1 -> resumeFromPlug()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handledInitialHeadsetPlug = true
|
||||||
|
}
|
||||||
|
|
||||||
// --- AUXIO EVENTS ---
|
// --- AUXIO EVENTS ---
|
||||||
ACTION_PLAY_PAUSE -> playbackManager.setPlaying(
|
ACTION_PLAY_PAUSE -> playbackManager.setPlaying(
|
||||||
!playbackManager.isPlaying
|
!playbackManager.isPlaying
|
||||||
|
|
Loading…
Reference in a new issue