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:
parent
49db7e0741
commit
2abc91674b
4 changed files with 29 additions and 28 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue