playback: simplify playbacknotification

Simplify the PlaybackNotification code to not have to pass Context for
an argument when it could simply be a private variable. This is okay,
as PlaybackNotification only lives as long as PlaybackService does.
This commit is contained in:
OxygenCobalt 2021-08-03 10:50:09 -06:00
parent 49db7e0741
commit 2abc91674b
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 29 additions and 28 deletions

View file

@ -21,10 +21,9 @@ class AudioReactor(
context: Context, context: Context,
private val player: SimpleExoPlayer private val player: SimpleExoPlayer
) : AudioManager.OnAudioFocusChangeListener { ) : AudioManager.OnAudioFocusChangeListener {
private val audioManager = context.getSystemServiceSafe(AudioManager::class)
private val settingsManager = SettingsManager.getInstance()
private val playbackManager = PlaybackStateManager.getInstance() private val playbackManager = PlaybackStateManager.getInstance()
private val settingsManager = SettingsManager.getInstance()
private val audioManager = context.getSystemServiceSafe(AudioManager::class)
private val request = AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN) private val request = AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN)
.setWillPauseWhenDucked(true) .setWillPauseWhenDucked(true)

View file

@ -14,7 +14,7 @@ import org.oxycblt.auxio.coil.loadBitmap
import org.oxycblt.auxio.music.Parent import org.oxycblt.auxio.music.Parent
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.LoopMode import org.oxycblt.auxio.playback.state.LoopMode
import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.ui.newBroadcastIntent import org.oxycblt.auxio.ui.newBroadcastIntent
import org.oxycblt.auxio.ui.newMainIntent import org.oxycblt.auxio.ui.newMainIntent
@ -25,9 +25,11 @@ import org.oxycblt.auxio.ui.newMainIntent
*/ */
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
class PlaybackNotification private constructor( class PlaybackNotification private constructor(
context: Context, private val context: Context,
mediaToken: MediaSessionCompat.Token mediaToken: MediaSessionCompat.Token
) : NotificationCompat.Builder(context, CHANNEL_ID), PlaybackStateManager.Callback { ) : NotificationCompat.Builder(context, CHANNEL_ID) {
val settingsManager = SettingsManager.getInstance()
init { init {
setSmallIcon(R.drawable.ic_song) setSmallIcon(R.drawable.ic_song)
setCategory(NotificationCompat.CATEGORY_SERVICE) setCategory(NotificationCompat.CATEGORY_SERVICE)
@ -47,16 +49,19 @@ class PlaybackNotification private constructor(
.setMediaSession(mediaToken) .setMediaSession(mediaToken)
.setShowActionsInCompactView(1, 2, 3) .setShowActionsInCompactView(1, 2, 3)
) )
// Don't connect to PlaybackStateManager here. This is because it's possible for this
// notification to not be updated by PlaybackStateManager before PlaybackService pushes
// the notification, resulting in invalid metadata.
} }
// --- STATE FUNCTIONS --- // --- STATE FUNCTIONS ---
/** /**
* Set the metadata of the notification using [song]. * Set the metadata of the notification using [song].
* @param colorize Whether to show the album art of [song] on the notification
* @param onDone What to do when the loading of the album art is finished * @param onDone What to do when the loading of the album art is finished
*/ */
fun setMetadata(context: Context, song: Song, colorize: Boolean, onDone: () -> Unit) { fun setMetadata(song: Song, onDone: () -> Unit) {
setContentTitle(song.name) setContentTitle(song.name)
setContentText(song.album.artist.name) setContentText(song.album.artist.name)
@ -66,7 +71,7 @@ class PlaybackNotification private constructor(
setSubText(song.album.name) setSubText(song.album.name)
} }
if (colorize) { if (!settingsManager.colorizeNotif) {
// loadBitmap() is concurrent, so only call back to the object calling this function when // loadBitmap() is concurrent, so only call back to the object calling this function when
// the loading is over. // the loading is over.
loadBitmap(context, song) { bitmap -> loadBitmap(context, song) { bitmap ->
@ -82,28 +87,28 @@ class PlaybackNotification private constructor(
/** /**
* Set the playing icon on the notification * Set the playing icon on the notification
*/ */
fun setPlaying(context: Context, isPlaying: Boolean) { fun setPlaying(isPlaying: Boolean) {
mActions[2] = buildPlayPauseAction(context, isPlaying) mActions[2] = buildPlayPauseAction(context, isPlaying)
} }
/** /**
* Update the first action to reflect the [loopMode] given. * Update the first action to reflect the [loopMode] given.
*/ */
fun setLoop(context: Context, loopMode: LoopMode) { fun setLoop(loopMode: LoopMode) {
mActions[0] = buildLoopAction(context, loopMode) mActions[0] = buildLoopAction(context, loopMode)
} }
/** /**
* Update the first action to reflect whether the queue is shuffled or not * Update the first action to reflect whether the queue is shuffled or not
*/ */
fun setShuffle(context: Context, isShuffling: Boolean) { fun setShuffle(isShuffling: Boolean) {
mActions[0] = buildShuffleAction(context, isShuffling) mActions[0] = buildShuffleAction(context, isShuffling)
} }
/** /**
* Apply the current [parent] to the header of the notification. * Apply the current [parent] to the header of the notification.
*/ */
fun setParent(context: Context, parent: Parent?) { fun setParent(parent: Parent?) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return
// A blank parent always means that the mode is ALL_SONGS // A blank parent always means that the mode is ALL_SONGS

View file

@ -48,7 +48,6 @@ import org.oxycblt.auxio.widgets.WidgetController
/** /**
* A service that manages the system-side aspects of playback, such as: * A service that manages the system-side aspects of playback, such as:
* - The single [SimpleExoPlayer] instance. * - The single [SimpleExoPlayer] instance.
* - The [MediaSessionCompat]
* - The Media Notification * - The Media Notification
* - Headset management * - Headset management
* - Widgets * - Widgets
@ -56,8 +55,6 @@ import org.oxycblt.auxio.widgets.WidgetController
* This service relies on [PlaybackStateManager.Callback] and [SettingsManager.Callback], * This service relies on [PlaybackStateManager.Callback] and [SettingsManager.Callback],
* so therefore there's no need to bind to it to deliver commands. * so therefore there's no need to bind to it to deliver commands.
* @author OxygenCobalt * @author OxygenCobalt
*
* TODO: Try to split up this god object somewhat, such as making the notification state-aware.
*/ */
class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callback, SettingsManager.Callback { class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callback, SettingsManager.Callback {
@ -246,7 +243,7 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
player.prepare() player.prepare()
notification.setMetadata( notification.setMetadata(
this, song, settingsManager.colorizeNotif, ::startForegroundOrNotify song, ::startForegroundOrNotify
) )
return return
@ -258,7 +255,7 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
} }
override fun onParentUpdate(parent: Parent?) { override fun onParentUpdate(parent: Parent?) {
notification.setParent(this, parent) notification.setParent(parent)
startForegroundOrNotify() startForegroundOrNotify()
} }
@ -272,13 +269,13 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
player.pause() player.pause()
} }
notification.setPlaying(this, isPlaying) notification.setPlaying(isPlaying)
startForegroundOrNotify() startForegroundOrNotify()
} }
override fun onLoopUpdate(loopMode: LoopMode) { override fun onLoopUpdate(loopMode: LoopMode) {
if (!settingsManager.useAltNotifAction) { if (!settingsManager.useAltNotifAction) {
notification.setLoop(this, loopMode) notification.setLoop(loopMode)
startForegroundOrNotify() startForegroundOrNotify()
} }
@ -286,7 +283,7 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
override fun onShuffleUpdate(isShuffling: Boolean) { override fun onShuffleUpdate(isShuffling: Boolean) {
if (settingsManager.useAltNotifAction) { if (settingsManager.useAltNotifAction) {
notification.setShuffle(this, isShuffling) notification.setShuffle(isShuffling)
startForegroundOrNotify() startForegroundOrNotify()
} }
@ -301,16 +298,16 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
override fun onColorizeNotifUpdate(doColorize: Boolean) { override fun onColorizeNotifUpdate(doColorize: Boolean) {
playbackManager.song?.let { song -> playbackManager.song?.let { song ->
notification.setMetadata( notification.setMetadata(
this, song, settingsManager.colorizeNotif, ::startForegroundOrNotify song, ::startForegroundOrNotify
) )
} }
} }
override fun onNotifActionUpdate(useAltAction: Boolean) { override fun onNotifActionUpdate(useAltAction: Boolean) {
if (useAltAction) { if (useAltAction) {
notification.setShuffle(this, playbackManager.isShuffling) notification.setShuffle(playbackManager.isShuffling)
} else { } else {
notification.setLoop(this, playbackManager.loopMode) notification.setLoop(playbackManager.loopMode)
} }
startForegroundOrNotify() startForegroundOrNotify()
@ -321,7 +318,7 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
connector.onSongUpdate(song) connector.onSongUpdate(song)
notification.setMetadata( notification.setMetadata(
this, song, settingsManager.colorizeNotif, ::startForegroundOrNotify song, ::startForegroundOrNotify
) )
} }
} }
@ -329,7 +326,7 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
override fun onQualityCoverUpdate(doQualityCovers: Boolean) { override fun onQualityCoverUpdate(doQualityCovers: Boolean) {
playbackManager.song?.let { song -> playbackManager.song?.let { song ->
notification.setMetadata( notification.setMetadata(
this, song, settingsManager.colorizeNotif, ::startForegroundOrNotify song, ::startForegroundOrNotify
) )
} }
} }

View file

@ -31,6 +31,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.logE import org.oxycblt.auxio.logE
import kotlin.reflect.KClass import kotlin.reflect.KClass
const val INTENT_REQUEST_CODE = 0xA0A0
// --- VIEW CONFIGURATION --- // --- VIEW CONFIGURATION ---
/** /**
@ -154,8 +156,6 @@ fun Context.showToast(@StringRes str: Int) {
Toast.makeText(applicationContext, getString(str), Toast.LENGTH_SHORT).show() Toast.makeText(applicationContext, getString(str), Toast.LENGTH_SHORT).show()
} }
const val INTENT_REQUEST_CODE = 0xA0A0
/** /**
* Create a broadcast [PendingIntent] * Create a broadcast [PendingIntent]
*/ */